2008.03_XUL – wieloplatformowy język opisu interfejsu użytkownika – część I_[Programowanie].pdf

(705 KB) Pobierz
439031814 UNPDF
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część II
XUL – wieloplatformowy
użytkownika – część II
Grzegorz Madajczak
W pierwszej części artykułu poznaliśmy podstawową strukturę języka XUL, liczne elementy służące do
budowy interfejsu graicznego użytkownika. Stworzony przez nas interfejs może wyglądać najbardziej
profesjonalnie, jednak będzie całkowicie bezużyteczny, jeśli nie dodamy do niego choćby odrobiny
funkcjonalności.
artykule konieczne jest zapoznanie się z lek-
turą pierwszej części artykułu oraz znajomość
podstaw dotyczących języka XML. Jeśli brak
Ci tej wiedzy – wróć proszę do poprzedniego numeru maga-
zynu Linux+ DVD, gdzie znajdują się dwa artykuły: część
pierwsza artykułu XUL – wieloplatformowy język opisu in-
terfejsu użytkownika oraz artykuł pt. Tworzenie dokumentów
XML dla początkujących . Dla sprawnego przyswajania za-
wartej w niniejszym artykule wiedzy konieczna jest również
podstawowa znajomość języka JavaScript.
na uzyskać stosując dwie ściśle połączone ze sobą tech-
niki – Obiektowy Model Dokumentu (DOM) oraz język
JavaScript.
Obiektowy Model Dokumentu i JavaScript
DOM – z ang. Document Object Model - to sposób re-
prezentacji złożonych dokumentów w postaci modelu
zorientowanego obiektowo. Oznacza to, że poszczegól-
ne elementy dokumentu są niepowtarzalnymi obiektami,
które mają swoje właściwości oraz metody. Odwołując
się do obiektów możemy zmieniać ich właściwości oraz
wywoływać metody im przypisane. Zasada działania
DOM polega na stworzeniu drzewa elementów w danym
dokumencie XUL. Elementem nadrzędnym do wszyst-
kich innych jest oczywiście element główny dokumen-
tu, w przypadku XUL – element < window >. Właśnie ze
względu na DOM ważne jest, aby każdy z elementów po-
siadał niepowtarzalną wartość atrybutu id , poprzez którą
będzie można do niego odwoływać się w DOM. W przy-
padku XUL DOM, jak w przypadku każdej innej odmia-
ny XML, opiera się na standardach narzuconych przez
organizację W3C.
Interaktywność GUI
Każde znane nam i działające GUI cechuje interaktyw-
ność. Polega to na tym, że na wywołane przez nas zda-
rzenie następuje reakcja programu, np. naciśnięcie przy-
cisku otworzy inne okno, zapisze wpisany do pola teksto-
wego łańcuch znaków. Wydawać by się mogło, że uzyska-
nie takiego działania wymaga znacznych nakładów pracy.
Zależą one, co jest oczywiste, od złożoności realizowane-
go projektu, a także od sposobu realizacji zaplanowanych
działań. Interaktywność GUI napisanego w XUL moż-
40
marzec 2008
język opisu interfejsu
D la zrozumienia treści prezentowanych w tym
439031814.020.png 439031814.021.png 439031814.022.png 439031814.023.png
 
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część II
JavaScript to skryptowy, zorientowany
obiektowo język programowania opracowany
przez irmę Netscape na potrzeby tworzenia in-
teraktywnych stron internetowych. Pod koniec
lat 90. organizacja ECMA ( European associa-
tion for standardizing information and commu-
nication systems – Europejskie Stowarzyszenie
na rzecz Standaryzacji Systemów Informacyj-
nych i Komunikacyjnych ; dawniej ang. Europe-
an Computer Manufacturers Association – Eu-
ropejskie Stowarzyszenie Producentów Kom-
puterów) opracowała na podstawie JavaScript
w pełni sformalizowany język ECMAScript,
stosowany np. w SVG. Jednak różnice pomię-
dzy obydwoma odmianami tego języka są na
tyle nieznaczne, że w przypadku XML oba po-
jęcia często stosowane są zamiennie.
JavaScript oraz ECMAScript – w języ-
ku XML stanowią elementy nie podlegające
parsowaniu (są interpretowane bezpośrednio
przez przeglądarkę). W związku z tym po-
winny być umieszczane w sekcjach CDATA
lub w postaci encji, przy czym popularniej-
sze jest to pierwsze rozwiązanie. Inny spo-
sób umieszczania JavaScript w XML/XUL,
to wywołanie zewnętrznej biblioteki Java-
Script, zapisanej zwyczajowo w pliku z roz-
szerzeniem js . Biblioteki JavaScript mogą
znajdować się zarówno na lokalnym twar-
dym dysku lub też na zdalnym serwerze.
śniej miały do czynienia z HTML, z pewno-
ścią rozpoznają wywołanie metody onclick.
Metoda ta nasłuchuje zdarzenie naciśnię-
cia przycisku. W tym konkretnym przypad-
ku – zaprezentowanym na listingu 2, zdarze-
nie to wywoła akcję – otwarcie okna dialogo-
wego z tekstem. JavaScript w XUL obsługuje
zdecydowanie więcej zdarzeń, niż to jedno za-
prezentowane na Listingu 2. Ich krótkie omó-
wienie prezentuje Tabela 1.
Ograniczanie JavaScript do obsługi przy-
cisków w XUL można przyrównać do posia-
dania najnowszego Dodge'a Vipera i jeżdżenia
nim z maksymalną prędkością 50 km/h. Sytu-
acje tę można wyjaśnić jedynie brakiem umie-
jętności w posługiwaniu się tak mocna maszy-
ną. Aby nie było tak w odniesieniu do Java-
Script, postaram się poniżej przedstawić kilka
przydatnych funkcji JavaScript w zakresie ob-
sługi XML. Na koniec postaram się pokazać,
jak wykorzystać w praktyce zdobytą wiedzę.
– oznaczające element nadrzędny w stosun-
ku do obecnego oraz dziecko (z ang. child )
– oznaczające element podrzędny (potom-
ny) w stosunku do bieżącego. Zasadą jest, że
każdy element potomny ( child ) może posia-
dać tylko jeden element nadrzędny ( parent ),
natomiast element nadrzędny może posia-
dać wiele elementów podrzędnych (potom-
nych - child ). Analizując przykładowy do-
kument XML zaprezentowany na listingu 3,
można stwierdzić, że element „kontakt” jest
rodzicem w stosunku do elementów imie ,
nazwisko itd., a jednocześnie jest dzieckiem
w stosunku do elementu kontakty .
Poruszanie się
po drzewie węzłów DOM
JavaScript doskonale obsługuje DOM udo-
stępniając wiele funkcji pozwalających na
sprawne poruszanie w hierarchicznej struk-
turze węzłów dokumentu. Bieżący doku-
ment (węzeł nadrzędny) reprezentowany jest
przez słowo kluczowe document , zaś element
główny - documentElement . Tak więc kod
JavaScript określający dostęp do elementu
głównego dokumentu wygląda następująco:
XML DOM
Bazując na drzewiastej strukturze dokumen-
tu XML, DOM zakłada, że każdy z elemen-
tów dokumentu XML jest węzłem (z ang.
node ) – począwszy od dokumentu jako ca-
łości, aż do poszczególnych elementów, ich
wartości tekstowych oraz atrybutów i ich
wartości. Ważne jest również to, że poszcze-
gólne węzły zachowują swoją hierarchiczną
strukturę, odzwierciedlającą strukturę do-
kumentu XML. Dlatego też DOM wprowa-
dza takie pojęcie, jak rodzic (z ang. parent )
var element_glowny = document.documen
tElement;
Prosty przykład
Listing 2 prezentuje prosty przykład zastoso-
wania JavaScript w XUL. Osoby, które wcze-
Mając dostęp do węzłów dokumentu może-
my poruszać się w jego strukturze stosując
takie polecenia, jak parentNode , irstChild
oraz lastChild oznaczające odpowiednio:
Rysunek 1. Przykładowa aplikacja napisana w języku XUL
www.lpmagazine.org
41
439031814.001.png 439031814.002.png 439031814.003.png 439031814.004.png 439031814.005.png
 
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część II
węzeł nadrzędny, pierwszy węzeł podrzęd-
ny i ostatni węzeł podrzędny. Jeśli nie chce-
my przekopywać się przez kolejne węzły do-
kumentu, możemy zastosować fukcję getE-
lementsByTagName() , która zwraca listę ele-
mentów o nazwie znacznika, będącego argu-
mentem wywołanej funkcji, np.
Jeszcze raz podkreślę, że powyższa funk-
cja zwraca listę elementów, nie zaś pojedyn-
czy element. Lista ta dziedziczy właściwości
obiektu Array (tablica) JavaScript, w związ-
ku z czym wywołanie konkretnego elementu
listy polega na podaniu indeksu elementu w
nawiasie kwadratowym, np.
var kontakt_elements = document.getEl
ementsByTagName(„kontakt”);
Listing 1. Osadzanie JavaScript w XML
< ? xml version=”1.0” encoding=”iso-8859-2” ? >
var element = kontakt_elements[3];
< root_element >
< script src=”biblioteka_javascript.js” / >
Jeśli mamy całkowitą pewność, że w doku-
mencie występuje tylko jeden element o po-
danej nazwie znacznika (co nie musi być
pewne) – funkcja zwróci nam jednoelemen-
towy zbiór elementów. Wywołanie tego ele-
mentu będzie się odbywać poprzez wywoła-
nie pozycji listy o zerowym indeksie:
< script type=”text/javascript” >
< ![CDATA[
alert(„Komunikat”);
]] >
< /script >
< /root_element >
var element = kontakt_element[0];
Listing 2. Prosta obsługa przycisku w JavaScript
< ?xml version= "1.0" encoding= "iso-8859-2" ? >
< ?xml-stylesheet href= "chrome://global/skin/" type= "text/css" ? >
Nieco podobnie do wyżej zaprezentowanej
funkcji działa polecenie childNodes , z tym
że zwraca ono listę węzłów potomnych (dzie-
ci) w stosunku do bieżącego:
< window
id= "main"
title= "Przykład"
xmlns= "http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul" >
var lista_elementow = document.docume
ntElement.childNodes;
Powyższe polecenie w stosunku do przykłado-
wego dokumentu XML z listingu 3 zwróci li-
stę zawierającą tylko jeden element – kontakt .
< vbox lex= "1" >
< button
label= "Przycisk"
onclick= "alert('To działa');" / >
< /vbox >
Wartości elementów i atrybutów
Przedstawione powyżej funkcje służą jedynie
odnalezieniu właściwego elementu dokumentu
XML, który przechowuje potrzebne nam dane.
Dane te mogą być zapisane jako tekstowy ele-
ment potomny (element typu PCDATA) lub w
postaci wartości atrybutu. Obydwa typy danych
są dostępne z poziomu JavaScript. Najprostszą
formą wywołania wartości elementu jest za-
stosowanie polecenia nodeValue . Zwraca ono
wartość elementu bieżącego, np.
< /window >
Listing 3. Przykładowy dokument XML
< ?xml version= "1.0" encoding= "iso-8859-2" ? >
< !DOCTYPE kontakty SYSTEM "data.dtd" >
< kontakty >
< kontakt >
var wartosc = document.documentEleme
nt.childNodes[0].nodeValue;
< imie/ >
< nazwisko/ >
< email/ >
< adr_sluzb/ >
< adr_dom/ >
< tel_sluzb/ >
< tel_dom/ >
Rezultatem działania powyższego polecenia jest
wartość pierwszego elementu potomnego w sto-
sunku do elementu głównego dokumentu. Takie
wywołanie wartości elementu kryje jednak w so-
bie pewną pułapkę. Jeśli spojrzymy na przykła-
dowy dokument XML z Listingu 3, zobaczy-
my, że powyższe polecenie powinno zwrócić
nam listę elementów potomnych elementu kon-
takt . Dzieje się tak, gdyż polecenie nodeValue
nie troszczy się o rodzaj zwracanej wartości. Jest
to olbrzymia wada (nie jedyna zresztą) parsera
XML dostarczanego przez JavaScript. Chcąc
< /kontakt >
< /kontakty >
42
marzec 2008
439031814.006.png 439031814.007.png 439031814.008.png 439031814.009.png
 
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część II
wymóc zwracanie wartości tekstowej zamiast
polecenia nodeValue należy zastosować polece-
nie data , przy czym w przypadku niekompaty-
bilnego formatu danych, polecenie to spowodu-
je powstanie błędu. Pozyskiwanie wartości atry-
butu jest nieco prostsze, co spowodowane jest
faktem, że wartość ta zawsze ma typ tekstowy.
Wystarczy wywołać funkcję getAttribute() ,
której argumentem jest nazwa atrybutu, np.
Listing 4. Dokument z Listingu 3., zapełniony danymi
< ?xml version= "1.0" encoding= "iso-8859-2" ? >
< !DOCTYPE kontakty SYSTEM "data.dtd" >
< kontakty >
< kontakt >
< imie >
Grzegorz
< /imie >
< nazwisko >
Madajczak
< /nazwisko >
< email >
madajczak@gmail.com
< /email >
< adr_sluzb >
Redakcja Linux+ ul. Bokserska 8 Wraszawa
< /adr_sluzb >
< adr_dom >
ul. Jodłowa 1/8 Warszawa
< /adr_dom >
< tel_sluzb >
22 5421787
< /tel_sluzb >
< tel_dom >
22 8856543
< /tel_dom >
var wratosc = element.getAttribute('n
azwa_atrybutu');
Manipulowanie węzłami DOM
JavaScript, dzięki zaimplementowanej pełnej
obsłudze DOM udostępnia liczne metody dzię-
ki którym możemy wstawiać, usuwać, czy też
w dowolny inny sposób manipulować elemen-
tami dokumentu XML.Najprostszą sytuacją
jest ustawienie wartości istniejącego atrybutu.
Analogicznie do poprzedniego przykładu funk-
cja ta wygląda następująco:
element.setAttribute('nazwa_atrybutu',
'wartość atrybutu');
Funkcja setAttribute() wywoływana jest za-
wsze z dwoma argumentami – nazwa atrybutu
oraz wartością tegoż atrybutu. Zadanie to może
być zrealizowane w nieco odmienny sposób – po-
przez jego rozbicie na trzy etapy. Pierwszy z nich
polega na utworzeniu nowego węzła – atrybutu:
< /kontakt >
< kontakt >
var newatt=document.createAttribute('
nazwa_atrybutu');
< imie >
Jan
< /imie >
< nazwisko >
Kowalski
< /nazwisko >
< email >
kowalski@gmail.com
< /email >
< adr_sluzb >
Sklep komputerowy "software" ul. Marszałkowska 16, Warszawa
< /adr_sluzb >
< adr_dom >
ul. Poznańska 78/6, Wraszawa
< /adr_dom >
< tel_sluzb >
22 7655429
< /tel_sluzb >
< tel_dom >
509876232
< /tel_dom >
Kolejny etap pracy polega na przypisaniu war-
tości do atrybutu
newatt.value = 'wartość atrybutu';
Na sam koniec przypisujemy atrybut do kon-
kretnego elementu:
konkretny_element.setattributeNode(n
ewatt);
Obydwa powyższe przykłady dotyczą sy-
tuacji, w której tworzymy nowy atrybut i
przypisujemy mu nową wartość. W sytu-
acji, gdy chcemy zmienić wartość już ist-
niejącego atrybutu należy również posłu-
żyć się funkcją setAttribute() . Tworzenie
nowego elementu wymaga przede wszystkim
użycia funkcji createElement() , której argu-
mentem jest nazwa elementu:
var newElement = document.createEleme
nt('nazwa_elementu');
< /kontakt >
< /kontakty >
www.lpmagazine.org
43
439031814.010.png 439031814.011.png 439031814.012.png 439031814.013.png 439031814.014.png 439031814.015.png
 
Rozwiązania
XUL – wieloplatformowy język opisu interfejsu użytkownika – część II
Tak stworzony element nie jest w żaden spo-
sób wpisany w strukturę dokumentu XML.
Aby tego dokonać należy wskazać, do któ-
rego z istniejących elementów przypiszemy
nowy element potomny. Służy do tego funk-
cja appendChild() :
newElement.appendData('Wartość węzła
tekstowego');
ny został na omawianym wcześniej Listingu 3. Po
wprowadzeniu przykładowych danych uzyska-
my dokument, jak na Listingu 4. Do pliku tego
stworzyłem dodatkowo plik DTD, który jednak
nie jest potrzebny w odniesieniu do parsera XML
oferowanego przez JavaScript. Ja jednak z zasady
zawsze tworzę DTD do XML, do czego gorąco
namawiam. Na Listingu 5. znajduje się kod goto-
wej aplikacji napisany w XUL. Jest to bardzo pro-
sty przykład – GUI składa się z dwóch sąsiadują-
cych paneli rozdzielonych splitterem. Lewy panel
to lista, prawy zaś to formularz składający się z
kilku pól tekstowych. Prawdziwe serce programu
stanowi jednak kod przedstawiony na Listingu 6.
Jest to niewielka biblioteka kilku skryptów Java-
Script napisanych na potrzeby aplikacji.
Dotychczas zajmowaliśmy się sytuacjami, w
których trzeba było dodać nowy węzeł lub
zmodyikować już istniejący. W pracy z do-
kumentem XML (także XUL) może okazać
się konieczne usunięcie jakiegoś elementu do-
kumentu. JavaScript wraz DOM udostępnia-
ją pełną gamę funkcji pozwalających również
na realizację tego zamierzenia. Usunięcie po-
jedynczego elementu odbywa się poprzez wy-
wołanie funkcji removeChild() , której argu-
mentem jest nazwa usuwanego węzła.
istniejący_element.appenChild(newEle
ment);
Powyższa funkcja dodaje kolejny element
potomny na koniec już istniejących, do
wskazanego elementu – rodzica. Nieco od-
miennie postępujemy z węzłami tekstowy-
mi. Nowy węzeł tekstowy tworzymy przy
użyciu funkcji createTextNode() , której ar-
gumentem jest tekst będący wartością węzła
tekstowego. Po utworzeniu węzła, podobnie
do poprzednio zaprezentowanego rozwiąza-
nia, należy przypisać go do istniejącego ele-
mentu. Służy do tego znana już funkcja ap-
pendChild() .
element_rodzic.removeChild('nazwa_
elementu_do_usuniecia');
Ładowanie dokumentu XML
Ze skryptów przedstawionych na Listingu 6,
najważniejsza jest chyba funkcja getXMLDa-
ta() . Jej zadaniem jest załadowanie zewnętrz-
nego pliku XML ( data.xml – Listing 4) zawie-
rającego dane o kontaktach. Skrypt ten wyko-
rzystuje funkcję tworzenia dokumentu XML
dostarczoną przez biblioteki JavaScript, zaim-
plementowane w przeglądarkach z silnikiem
Gecko (między innymi Mozilla, Firefox ). Dla-
tego też funkcja ta nie będzie działała w prze-
glądarce InternetExplorer, co związane jest to z
odmiennym silnikiem parsującym XML dostar-
czanym przez tą przeglądarkę. Ogólna struktu-
ra tej funkcji wygląda następująco:
Nieco inaczej postępujemy, jeśli usuwanym wę-
złem jest węzeł tekstowy. W tej sytuacji nale-
ży zastosować funkcję deleteData() . Nato-
miast gdy chcemy usunąć atrybut przypisany
do elementu - należy zastosować funkcję re-
moveAttribute() , której argumentem jest na-
zwa atrybutu.
var textNode = document.createTextNod
e('Wartość węzła tekstowego');
istniejacy_element.appendChild(textN
ode);
istniejacy_element.removeAttribute('n
azwa_atrybutu');
Powyższe rozwiązanie może zostać nieco
skrócone poprzez zastosowanie funkcji spe-
cyicznej tylko dla wartości tekstowych ele-
mentów- appendData() , której argumen-
tem jest również wartość węzła tekstowego.
Funkcja ta jest niejako połączeniem dwóch
powyższych.
Na co to wszystko?
Znamy już dość dużo, aby połączyć zdobytą wie-
dzę z zakresu programowania w XUL i wiedzę na
temat obsługi XML DOM przez JavaScript. Aby
zobrazować opisane powyżej funkcje postanowi-
łem napisać aplikację w XUL, której zadaniem
będzie zarządzanie bazą istniejących kontaktów
(Rysunek 1). Dane o kontaktach zostały zapisa-
ne w pliku XML, którego szkielet zaprezentowa-
var xmlDoc=document.implementation.cr
eateDocument("ns","root",null);
var newElement = document.createEleme
nt('nowy_element');
Jako argumenty funkcji podajemy kolejno do-
myślną przestrzeń nazw oraz nazwę głównego
Tabela 1. Zdarzenia obsługiwane w XUL przez JavaScript
Zdarzenie
Opis
onclick
Zdarzenie wywoływane po kliknięciu (naciśnięcie i zwolnienie przycisku myszki) na element okna.
onmousedown
Zdarzenie wywołane po naciśnięciu przycisku myszy. Nie ma znaczenia, czy przycisk zostanie zwolniony.
onmouseup
Zdarzenie wywołane po zwolnieniu przycisku myszy.
onmouseover
Zdarzenie wywołane obecnością wskaźnika myszy nad elementem okna.
onmousemove
Zdarzenie wywołane ruchem wskaźnika myszy nad elementem okna.
onmouseover
Zdarzenie wywołane opuszczeniem wskaźnika myszy elementu okna.
oncommand
Zdarzenie wywołane w momencie wybrania przycisku lub pozycji menu. Zdarzenie to różni się od onclick tym, że
wywołane może być również wybraniem skrótu klawiaturowego przypisanego do przycisku, czy pozycji menu.
onkeypress
Zdarzenie wywołane w chwili naciśnięcia i puszczenia klawisza, w chwili, gdy element okna jest zaznaczony.
onkeydown
Zdarzenie wywołane w chwili naciśnięcia klawisza, w chwili, gdy element okna jest zaznaczony.
onkeyup
Zdarzenie wywołane w chwili puszczenia klawisza, w chwili, gdy element okna jest zaznaczony.
onfocus
Zdarzenie wywołane w momencie, gdy element okna otrzyma fokus.
onblur
Zdarzenie wywołane w momencie utracenia zaznaczenia – fokusu.
onload
Zdarzenie wywołane w momencie załadowania okna (pierwszego otwarcia).
onunload
Zdarzenie wywołane w momencie zamykania okna.
44
marzec 2008
439031814.016.png 439031814.017.png 439031814.018.png 439031814.019.png
 
Zgłoś jeśli naruszono regulamin