2008.04_XUL – część III_[Programowanie].pdf
(
766 KB
)
Pobierz
439032486 UNPDF
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część III
XUL – część III
Grzegorz Madajczak
W pierwszej części minicyklu artykułów poświęconych XUL poznaliśmy poszczególne komponenty
służące do budowy graicznego interfejsu użytkownika. Drugi artykuł opisywał zagadnienia integracji
poszczególnych elementów oraz zaznajomił nas z podstawami użycia
JavaScript
do obsługi zdarzeń w
XUL. W ostatnim artykule z tego cyklu dowiemy się więcej na temat łączenia XUL z innymi odmianami
języka XML oraz zmiany wyglądu interfejsu z użyciem kaskadowych arkuszy stylu.
sposób można połączyć XUL z innymi
odmianami języka XML. Zapoznamy
się pokrótce z mechanizmem
XPCOM
,
znacznie rozszerzającym możliwości tandemu XUL + Ja-
vaScript, a na koniec zajmiemy się również wprowadza-
niem zmian do wyglądu interfejsu, tak aby wyglądał on
inaczej niż standardowy, nieco siermiężny styl
chrome
.
Wszystkiego tego dowiemy się na przykładzie prostej
aplikacji – galerii do przeglądania plików graicznych.
Kod tej aplikacji będzie zaprezentowany na kolejnych li-
stingach i w miarę potrzeby omówiony, natomiast pliki
źródłowe znajdują się na stronie
www.lpmagazine.org
w
katalogu
XUL
/
przyklad
.
nazw w głównym elemencie <
window
> aplikacji. Zwią-
zane jest to z użyciem trzech różnych odmian języka
XML, dla których musimy zdeiniować zakres przestrze-
ni nazw – dla każdego z osobna. Całkowitą nowością jest
natomiast fragment kodu znajdujący się pomiędzy znacz-
nikiem otwierającym i zamykającym <
svg:svg
>. O jego
funkcji napiszę za chwilę. Do stworzenia aplikacji wy-
korzystano najnowszą specyikację języka XUL, zaim-
plementowaną w przeglądarce
Firefox
-
3.0
, która na razie
jest w fazie rozwojowej. Wersja ta wprowadza między
innymi kontrolkę <
scale
>, która tworzy suwak.
Omawiana aplikacja jest prostą przeglądarką ob-
razków. Uruchomienie aplikacji otwiera okno dialogo-
we, w którym należy wybrać folder z plikami graiczny-
mi. Obrazki z folderu zostaną wstawione jako elementy
listy w lewym panelu aplikacji. Interfejs graiczny skła-
da się z paska narzędzi (<
toolbox
>) oraz z dwóch paneli
z rozdzielaczem (<
splitter
>). Wszystkie te elementy zo-
stały omówione w poprzednich częściach minicyklu po-
święconego XUL. Na pasku narzędzi znajdują się przy-
ciski (<
toolbarbutton
>), obsługujące poszczególne funk-
cje związane z działaniem aplikacji – otwieraniem ob-
Opis aplikacji
Kod interfejsu aplikacji, widocznej na Rysunku 1.,
przedstawia Listing 1. Kod biblioteki
JavaScript
z funk-
cjami obsługującymi interfejs przedstawia Listing 2.
Przeglądając kod XUL z Listingu 1., większość elemen-
tów powinna wyglądać znajomo, poza niewielkimi no-
winkami. Jedną z nich jest deklaracja kilku przestrzeni
50
kwiecień 2008
W
obecnym artykule zobaczymy, w jaki
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część III
Listing 1.
Kod graicznego interfejsu użytkownika aplikacji
Galeria
napisany w języku XUL
<?xml version="1.0" encoding="iso-8859-2"?>
orient=
"horizontal"
onchange=
"magnify()"
/
>
<
label id=
"scaleValue"
value=
"100"
/
>
<
label value=
"%"
/
>
<
toolbarseparator
/
>
<
?xml-stylesheet href=
"gallery.css"
type=
"text/css"
?
>
<
window
id=
"main"
title=
"Galeria obrazków"
xmlns=
"http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul"
xmlns:svg=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<
toolbarbutton image=
"img/help.png"
onclick
=
"window.open('help.xul')"
/
>
<
/hbox
>
<
/toolbar
>
<
/toolbox
>
<
script type=
"text/javascript"
src=
"library.js"
/
>
<
toolbox
>
<
toolbar
>
<
hbox lex=
"1"
class=
"tb"
align=
"center"
>
<
hbox lex=
"1"
>
<
listbox id=
"lista"
onclick=
"setImage()"
/
>
<
splitter
id=
"identiier"
state=
"open"
collapse=
"before"
resizebefore=
"closest"
resizeafter=
"closest"
>
<
grippy
/
>
<
/splitter
>
<
toolbarbutton image=
"img/ileopen.png"
oncommand=
"openImage()"
/
>
<
toolbarbutton image=
"img/previous.png"
oncommand=
"nextprev(-1)"
/
>
<
toolbarbutton image=
"img/next.png"
oncommand=
"nextprev(1)"
/
>
<
vbox
>
<
svg:svg width=
"600"
height=
"450"
>
<toolbarbutton image="img/left.png"
oncommand="move('left')" />
<
svg:g id=
"moveEl"
>
<
svg:g id=
"rotateEl"
>
<
svg:image
id=
"svgimg"
xlink:href=
""
width=
"600"
height=
"450"
/
>
<
/svg:g
>
<
/svg:g
>
<
/svg:svg
>
<
/vbox
>
<
/hbox
>
<
toolbarbutton image=
"img/up.png"
oncommand=
"move('up')"
/
>
<
toolbarbutton image=
"img/down.png"
oncommand=
"move('down')"
/
>
<
toolbarbutton image=
"img/right.png"
oncommand=
"mov('right')"
/
>
<
toolbarbutton image=
"img/redo.png"
onclick=
"rotate('left')"
/
>
<
toolbarbutton image=
"img/undo.png"
onclick=
"r
otate('right')"
/
>
<
script type=
"text/javascript"
>
<
![CDATA[
loaddata();
var mirrorVal = new Array(1,1);
var pozX = 0;
var pozY =
0;
var rotation = 0;
var imgWidth = parseInt(document.getElementById
(
"svgimg"
).getAttribute(
"width"
));
var imgHeight = parseInt(document.getElementByI
d(
"svgimg"
).getAttribute(
"height"
));
var idx = 0;
]]
>
<
/script
>
<
toolbarbutton image=
"img/odbij.png"
onclick
=
"mirror('poziom')"
/
>
<toolbarbutton image="img/odbij_poziom.png"
onclick="mirror('pion')"/>
<
label value=
"Powiększenie: "
/
>
<
scale id=
"magnifyScale"
min=
"10"
max=
"100"
increment=
"10"
value=
"100"
</window>
www.lpmagazine.org
51
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część III
razków, poruszaniem się na liście obrazków
(lewy panel) oraz przekształceniami po-
większonego obrazka wybranego z listy.
domyślną, jak w przykładzie powyżej. No-
wa domyślna przestrzeń nazw będzie obo-
wiązywała do zamknięcia znacznika, który
ją zdeiniował. Kod pomiędzy znacznikiem
otwierającym, a zamykającym interpreto-
wany będzie na podstawie nowo zdeinio-
wanej przestrzeni nazw.
W omawianej aplikacji SVG, jak już
wspomniałem, służy do przekształceń grai-
ki rastrowej (obrazka) wyświetlanej w głów-
nym oknie programu. Funkcje przekształca-
jące zawarte są w bibliotece JavaScript. Nie
jest to odpowiednie miejsce na omawianie
języka SVG, lecz nie sposób wspomnieć o
mechanizmach zastosowanych w aplika-
cji. Więcej informacji na temat SVG można
znaleźć w artykule
SVG do tworzenia stron
internetowych
, który ukazał się na łamach
magazynu
Linux+
w kwietniu 2007 roku (nr
4/2007 (120)). Na potrzeby obecnego arty-
kułu omówię jedynie zastosowane w przy-
kładowej aplikacji funkcje.
Pierwsza z funkcji przekształcających
obrazek zaimplementowana jest w funkcji
JavaScript o nazwie
magnify()
. Funkcja ta,
korzystając z modelu DOM wyszukuje ele-
ment o żądanym ID – w tym wypadku ele-
ment
image
będący znacznikiem wstawiają-
cym obrazek do dokumentu. Funkcja
ma-
gnify()
wstawia do tego elementu atrybut
transform
- odpowiedzialny za przekształce-
nia obiektów w SVG. W tym przypadku wy-
konujemy przekształcenie na podstawie ma-
cierzy. Więcej na ten temat można znaleźć
w dokumentacji poświęconej przekształ-
ceniom w SVG na stronach W3C:
http:
//www.w3.org/TR/SVG/coords.html#Trans-
formAttribute
. Przekształcenia obiektu SVG
na podstawie macierzy wykorzystuje rów-
nież inna funkcja:
miror()
- służąca do od-
bijania obrazka w poziomie i w pionie. Po-
zostałe dwie funkcje –
rotate()
- obraca-
jąca obrazek o 90° - oraz move() przesuwa-
jąca obrazek w pionie i w poziomie wyko-
rzystują również podstawianie wartości do
atrybutu
transform
- wykorzystując odpo-
wiednie funkcje zaimplementowane w ję-
zyku SVG.
Powyższe zastosowanie SVG w XUL to
w sumie ambitne zadanie. Nie zaprzeczam,
że opanowanie przekształceń w SVG na po-
ziomie kodu wymaga nieco wiedzy. Zdecy-
dowanie prostszym przykładem jest zasto-
sowanie SVG do tworzenia elementów gra-
ficznych, np. ikon na przyciskach. Takie za-
stosowanie SVG prezentuje kod na Listin-
gu 3. W przykładzie tym przycisk o id
svg-
button
wykorzystuje możliwość wstawiania
obiektu pomiędzy znaczniki otwierający i
zamykający elementu
button
w XUL. W
tej konkretnej sytuacji wstawionym obiek-
tem jest kod SVG przedstawiający ikonę
– trzy nakładające się na siebie koła. Do-
łożenie do tego prostego skryptu zmienia-
jącego kolory kół tworzy bardzo efektow-
ny przycisk. Utworzenie takiego przyci-
sku stosując zwykła grafikę rastrową by-
łoby również możliwe, lecz zdecydowanie
mniej efektowne.
Wydawać by się mogło, że utworzenie ta-
kiego przycisku, zawierającego graikę SVG,
jest bardzo trudne – wymagające wiedzy na
temat SVG. Okazuje się jednak, że efektowne
elementy graiczne SVG możemy umieszczać
w aplikacji XUL posługując się dowolnym
edytorem graiki SVG, np. programem
Ink-
scape
. W tym celu należy stworzyć graikę,
posługując się szerokim wachlarzem narzę-
dzi dostarczanych przez program. Na koniec
graikę zapisujemy w czystym formacie SVG.
Teraz pozostało nam jedynie otworzenie pli-
ku
*.svg
w edytorze tekstowym, skopiowanie
kodu znajdującego się pomiędzy znacznikiem
otwierającym i zamykającym <
svg
> i wkleje-
nie go w wybrane miejsce dokumentu XUL,
np. pomiędzy znacznik otwierający i zmyka-
jący <
button
>. Ostatecznie modyikujemy de-
klarację przestrzeni nazw – i gotowe...
Łatwo zauważyć, że JavaScript nie roz-
różnia, który z elementów jest elementem
kodu SVG, a który elementem kodu XUL.
Dla JavaScript wszystkie one są elementa-
mi, które mają swoje ściśle określone miej-
sce w modelu dokumentu. Podobnie bę-
dzie z każdym innym językiem pochodnym
XML, który wprowadzimy do XUL.
XUL i SVG
– w jednym stali DOMu
Ciekawostką aplikacji jest zastosowanie ję-
zyka SVG, jako silnika do przekształceń
obrazka. SVG – język skalowalnej graiki
wektorowej, udostępnia bowiem wiele funk-
cji pozwalających na przekształcanie grai-
ki rastrowej. Funkcje te nie są tak rozbudo-
wane, jak w przypadku profesjonalnych pro-
gramów graicznych, lecz i tak oferują du-
żo więcej, niżby można było się spodziewać
po aplikacji napisanej z użyciem dostępnych
nam metod.
Zastosowanie SVG we wnętrzu kodu
XUL jest dobrym przykładem na możliwość
mieszania różnych odmian XML w jednym
dokumencie. W omawianym przypadku SVG
znalazło się we wnętrzu XUL. Stosując taką
mieszankę należy pamiętać o zdeiniowaniu
przestrzeni nazw języków stosowanych w da-
nym dokumencie, a następnie odwoływanie
się do nich przy użyciu przedrostków, np.
<svg:svg width="600" height="450"
xmlns="http://www.w3.org/2000/svg">
<!-- Kod SVG -->
</svg:svg>
Aby uniknąć konieczności ciągłego stoso-
wania przedrostka przestrzeni nazw, moż-
na zdeiniować ją ponownie w elemencie
nadrzędnym dla danego kodu i uczynić ją
Rysunek 1.
Przykładowa aplikacja napisana w XUL, omawiana w bieżącym artykule
52
kwiecień 2008
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część III
Listing 2.
Kod biblioteki funkcji JavaScript obsługujących GUI aplikacji.
function getFiles()
{
var
fp
=
Components.classes["@mozilla.org
/
ilepicker
;
1
"].createIns
tan
ce(nsIFilePicker);
fp.appendFilters(nsIFilePicker.ilterImages)
;
fp.init(window, "Select a File
",
nsIFilePicker.modeOpen);
var
res
=
fp.show()
;
if
(res
==
nsIFilePicker.returnOK)
{
var
path
=
fp.ile.path
;
var
listaElement
=
document.getElementById(
"lista"
)
;
var
newItemEl
=
document.createElement(
"listitem
"
)
;
var
img
=
document.createElement("image
");
img.setAttribute(
"src"
, path)
;
img.setAttribute(
"width"
, "
200
");
img.setAttribute(
"height"
, "
150
");
img.setAttribute("
onclick
","
setImage()
;
");
newItemEl.appendChild(img)
;
listaElement.appendChild(newItemEl)
;
var
image
=
document.getElementById(
"svgimg"
)
;
image.setAttribute(
"xlink:href"
, path)
;
}
}
try
{
netscape.security.PrivilegeManager.enablePrivilege(
"Uni
versalXPConnect"
)
;
}
catch (e)
{
alert(
"Brak uprawnien do odczytu / zapisu
lokalnych plikow"
)
;
}
var
startPath
;
var
nsIFilePicker
=
Components.interfaces.nsIFilePic
ker
;
var
fp
=
Components.classes["@mozilla.org
/
ilepicker
;
1
"].createIns
tan
ce(nsIFilePicker);
fp.init(window, "Select a File
", nsIFilePicker.modeG
etFolder);
var
res
=
fp.show()
if
(res
==
nsIFilePicker.returnOK)
{
startPath
=
fp.ile.path
;
}
var
ile
=
Components.classes["@mozilla.org
/
ile
/
local
;
1
"].createIns
tan
ce(Components.interfaces.nsILocalFile);
function loaddata()
{
var
photos
=
getFiles()
;
var
listaElement
=
document.getElementById(
"lista"
)
;
ile.initWithPath(startPath)
;
var
entries
=
ile.directoryEntries
;
var
Farray
=
[]
;
while
(entries.hasMoreElements())
{
var
entry
=
entries.getNext()
;
entry.QueryInterface(Components.interfaces.nsIFi
le)
;
Farray.push(entry.path)
;
}
return
Farray
;
}
for
(i
=
0
;
i
<
photos.length
;
i++)
{
var
newItemEl
=
document.createElement(
"listitem
"
)
;
var
img
=
document.createElement("image
");
img.setAttribute(
"src"
, photos[i])
;
img.setAttribute(
"width"
, "
200
");
img.setAttribute(
"height"
, "
150
");
img.setAttribute("
onclick
","
setImage()
;
");
newItemEl.appendChild(img)
;
listaElement.appendChild(newItemEl)
;
}
}
function openImage()
{
try
{
netscape.security.PrivilegeManager.enablePrivilege
(
"UniversalXPConnect"
)
;
}
catch (e)
{
alert(
"Brak uprawnien do odczytu / zapisu
lokalnych plikow"
)
;
}
var
path
;
var
nsIFilePicker
=
Components.interfaces.nsIFilePic
ker
;
function setImage()
{
var
lista
=
document.getElementById(
"lista"
)
;
var
image
=
document.getElementById(
"svgimg"
)
;
var
imageSrc
=
lista.childNodes[lista.selectedIndex].
childNodes[
0
].getAttribute(
"src"
)
;
image.setAttribute(
"xlink:href"
, imageSrc)
;
idx
=
lista.selectedIndex
;
}
function magnify()
{
var
image
=
document.getElementById(
"svgimg"
)
;
var
scale
=
document.getElementById(
"magnifyScale"
)
;
www.lpmagazine.org
53
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część III
Listing 2b.
Kod biblioteki funkcji JavaScript obsługujących GUI aplikacji
XML w XUL
Wielokrotnie podkreślałem, że jedną z na-
czelnych cech języków pochodnych od
XML, jest możliwość wzajemnego prze-
platania się w jednym dokumencie. W po-
przednim rozdziale artykułu omawiałem
sytuację, gdy SVG jest wtrącone do kodu
XML. Przeglądając kod na Listingu 3. moż-
na zobaczyć, że znajduje się tam fragment
kodu w XHTML tworzący tabelę. Z równą
łatwością można stosować każdy inny ele-
ment języka XHTML, jak i każdy inny język
pochodny XML, np.
MathML
, czy
XForms
(więcej o tych językach m. in. na stronie
http://www.w3schools.com
).
Możliwa jest również sytuacja odwrot-
na, kiedy to kod XUL znajduje się we-
wnątrz innego języka XML. Takie rozwią-
zanie można odnaleźć w dokumencie
ne-
sted_xul.xhtml
, który znajduje się w folde-
rze
XUL
/
przyklad
na płycie dołączonej do
czasopisma. Przy takim rozwiązaniu należy
jednak liczyć się z tym, że nie wszystkie ele-
menty XUL będą prawidłowo działały.
var
scaleLabel
=
document.getElementById(
"scaleValue"
)
;
var
imageGr
=
document.getElementById(
"moveEl"
)
;
scaleLabel.setAttribute(
"value"
, scale.value)
;
var
sxy
=
scale.value
/
100
;
imgWidth
=
600
* scale.value
/
100
;
imgHeight
=
450
* scale.value
/
100
;
pozX
=
(
600
– imgWidth)
/
2
;
pozY
=
(
450
– imgHeight)
/
2
;
imageGr.setAttribute(
"transform"
,
"matrix("
+ sxy + ",
0
,
0
,
" + sxy + "
,
" +
pozX + "
,
" + pozY + "
)
");
}
function rotate(dir)
{
var
image
=
document.getElementById(
"rotateEl"
)
;
if
(dir
==
"right"
) rotation
=
rotation +
90
;
else
rotation
=
rotation –
90
;
image.setAttribute(
"transform"
,
"rotate("
+ rotation
+
")"
)
;
}
function mirror(dir)
{
var
image
=
document.getElementById(
"rotateEl"
)
;
var
imageMoveEl
=
document.getElementById(
"moveEl"
)
;
XPCOM
XPCOM (z ang.
Cross
Platform
Compo-
nent
Object
Model
) to międzyplatformowy
model komponentów podobnym do mecha-
nizmu
CORBA
znanego z
Gnome
lub
COM
irmy
Microsoft
. W przykładowej aplikacji
mechanizm XPCOM został wykorzystany
do otwierania folderu zawierającego grai-
kę oraz otwieranie pojedynczych plików
graicznych.
Mechanizm otwierający folder z plika-
mi graicznymi znajduje się w funkcji
get-
Files()
(Listing 2.). Pierwsze wiersze ko-
du funkcji stanowią kluczowy element całej
aplikacji. Funkcja
if
(dir
==
"poziom"
)
{
mirrorVal[
0
]
=
mirrorVal[
0
] * -
1
;
pozX
=
pozX - (imgWidth +
20
) * mirrorVal[
0
]
;
}
if
(dir
==
"pion"
)
{
mirrorVal[
1
]
=
mirrorVal[
1
] * -
1
;
pozY
=
pozY - (imgHeight +
20
) * mirrorVal[
1
]
;
}
image.setAttribute(
"transform"
,
"matrix("
+ mirrorVal[
0
] + ",
0
,
0
," +
mirrorVal[
1
] +
","
+ pozX +
","
+ pozY +
")"
)
;
}
function move(dir)
{
var
imageMoveEl
=
document.getElementById(
"svgimg"
)
;
if
(dir
==
"up"
) pozY
=
pozY –
10
;
if
(dir
==
"down"
) pozY
=
pozY +
10
;
if
(dir
==
"right"
) pozX
=
pozX +
10
;
if
(dir
==
"left"
) pozX
=
pozX –
10
;
imageMoveEl.setAttribute(
"transform"
,
"translate("
+ pozX +
","
+ pozY +
")"
)
;
}
function nextprev(i)
{
var
image
=
document.getElementById(
"svgimg"
)
;
var
lista
=
document.getElementById(
"lista"
)
;
idx
=
idx + i
;
var
imageSrc
=
lista.childNodes[idx].childNodes[
0
].getAttribute(
"src"
)
;
image.setAttribute(
"xlink:href"
, imageSrc)
;
}
netscape.security.PrivilegeManager
.enablePrivilege("UniversalXPConne
ct");
włącza bowiem możliwość odczytu i zapisu
plików przez JavaScript za pośrednictwem
przeglądarki internetowej. Jeśli wcześniej
możliwość taka została zablokowana, poja-
wi się stosowny komunikat o braku upraw-
nień do powyższych czynności.
Pierwszym etapem wykorzystującym
mechanizm XPCOM jest utworzenie nowej
instancji komponentu
nsILocalFile
, obsłu-
gującego operacje wejścia/wyjścia strumie-
nia z/do pliku.
var nsIFilePicker = Components.inter
faces.nsIFilePicker;
54
kwiecień 2008
Plik z chomika:
SOLARIX33
Inne pliki z tego folderu:
2006.01_Koder plików w formacie OGG_[Programowanie].pdf
(722 KB)
2007.06_Piękno fraktali_[Programowanie].pdf
(1778 KB)
2008.11_GanttProject_[Programowanie].pdf
(1014 KB)
2007.04_USB Device Explorer_[Programowanie].pdf
(1134 KB)
2006.09_QT, PyQT – szybkie tworzenie baz danych_[Programowanie].pdf
(1319 KB)
Inne foldery tego chomika:
Administracja
Aktualnosci
Audio
Bazy Danych
Bezpieczenstwo
Zgłoś jeśli
naruszono regulamin