Wprowadzenie do AWT

Biblioteka klas języka programowania Java zawiera zestaw narzędzi interfejsu użytkownika o nazwie Abstract Windowing Toolkit lub AWT. AWT jest zarówno potężny, jak i elastyczny. Jednak nowicjusze często odkrywają, że jego moc jest ukryta. Opisy klas i metod znajdujące się w rozproszonej dokumentacji zawierają niewiele wskazówek dla nowego programisty. Ponadto dostępne przykłady często pozostawiają wiele ważnych pytań bez odpowiedzi. Oczywiście nowicjusze powinni spodziewać się pewnych trudności. Efektywne graficzne interfejsy użytkownika są z natury trudne do zaprojektowania i wdrożenia, a czasami skomplikowane interakcje między klasami w AWT tylko komplikują to zadanie. Jednak przy odpowiednich wskazówkach stworzenie graficznego interfejsu użytkownika przy użyciu AWT jest nie tylko możliwe, ale stosunkowo proste.

W tym artykule omówiono filozofię stojącą za AWT i omówiono praktyczne problemy związane z tworzeniem prostego interfejsu użytkownika dla apletu lub aplikacji.

Co to jest interfejs użytkownika

Interfejs użytkownika to ta część programu, która współdziała z użytkownikiem programu. Interfejsy użytkownika mają różne formy. Formy te mają różną złożoność, od prostych interfejsów wiersza poleceń do graficznych interfejsów użytkownika typu „wskaż i kliknij”, udostępnianych przez wiele nowoczesnych aplikacji.

Na najniższym poziomie system operacyjny przesyła informacje z myszy i klawiatury do programu jako dane wejściowe i dostarcza piksele na wyjście programu. AWT został zaprojektowany tak, aby programiści nie martwili się o szczegóły śledzenia myszy lub czytania klawiatury, ani też zajmowali się szczegółami pisania na ekranie. AWT zapewnia dobrze zaprojektowany zorientowany obiektowo interfejs dla tych usług i zasobów niskiego poziomu.

Ponieważ język programowania Java jest niezależny od platformy, AWT musi być również niezależny od platformy. AWT został zaprojektowany, aby zapewnić wspólny zestaw narzędzi do projektowania graficznego interfejsu użytkownika, które działają na różnych platformach. Elementy interfejsu użytkownika dostarczane przez AWT są implementowane przy użyciu natywnego zestawu narzędzi GUI każdej platformy, zachowując w ten sposób wygląd i działanie każdej platformy. To jeden z najmocniejszych punktów AWT. Wadą takiego podejścia jest fakt, że graficzny interfejs użytkownika zaprojektowany na jednej platformie może wyglądać inaczej, gdy jest wyświetlany na innej platformie.

Komponenty i pojemniki

Graficzny interfejs użytkownika jest zbudowany z elementów graficznych zwanych komponentami. Typowe komponenty obejmują takie elementy, jak przyciski, paski przewijania i pola tekstowe. Komponenty pozwalają użytkownikowi na interakcję z programem i dostarczają użytkownikowi wizualnej informacji zwrotnej o stanie programu. W AWT wszystkie komponenty interfejsu użytkownika są instancjami klasy Component lub jednego z jej podtypów.

Komponenty nie są samodzielne, ale znajdują się w kontenerach. Kontenery zawierają i kontrolują układ komponentów. Pojemniki same w sobie są komponentami i dlatego mogą być umieszczane wewnątrz innych pojemników. W AWT wszystkie kontenery są instancjami klasy Container lub jednego z jej podtypów.

Przestrzennie komponenty muszą całkowicie pasować do pojemnika, który je zawiera. To zagnieżdżenie komponentów (w tym kontenerów) w kontenerach tworzy drzewo elementów, zaczynając od kontenera u podstawy drzewa i rozszerzając się aż do liści, które są komponentami takimi jak przyciski.

Ilustracja na rysunku 1 przedstawia prosty graficzny interfejs użytkownika, który wyglądałby w systemie Windows 95. Rysunek 2 przedstawia elementy interfejsu z rysunku 1 w postaci drzewa.

Rodzaje komponentów

Rysunek 3 przedstawia zależność dziedziczenia między klasami komponentów interfejsu użytkownika udostępnianymi przez AWT. Class Component definiuje interfejs, do którego muszą przylegać wszystkie komponenty.

AWT udostępnia dziewięć podstawowych klas komponentów niebędących kontenerami, z których można zbudować interfejs użytkownika. (Oczywiście nowe klasy komponentów mogą pochodzić z któregokolwiek z nich lub z samej klasy Component.) Te dziewięć klas to: Button, Canvas, Checkbox, Choice, Label, List, Scrollbar, TextArea i TextField. Rysunek 4 przedstawia instancję każdej klasy.

Aby wyświetlić ten aplet, potrzebujesz przeglądarki obsługującej język Java.

Rysunek 4.

Dziewięć elementów interfejsu użytkownika

Źródło tego ekranu znajduje się tutaj.

Rodzaje pojemników

AWT oferuje cztery klasy kontenerów. Są to klasa Window i jej dwa podtypy - klasa Frame i klasa Dialog - oraz klasa Panel. Oprócz kontenerów udostępnianych przez AWT, klasa Applet jest kontenerem - jest podtypem klasy Panel i dlatego może zawierać komponenty. Poniżej przedstawiono krótkie opisy każdej klasy kontenera dostarczonej przez AWT.

Okno Powierzchnia wyświetlania najwyższego poziomu (okno). Instancja klasy Window nie jest dołączona ani osadzona w innym kontenerze. Instancja klasy Window nie ma obramowania ani tytułu.
Rama Powierzchnia wyświetlania najwyższego poziomu (okno) z obramowaniem i tytułem. Instancja klasy Frame może mieć pasek menu. Poza tym jest bardzo podobny do instancji klasy Window.
Dialog Powierzchnia wyświetlania najwyższego poziomu (okno) z obramowaniem i tytułem. Instancja klasy Dialog nie może istnieć bez skojarzonej instancji klasy Frame.
Płyta

Ogólny pojemnik do przechowywania komponentów. Instancja klasy Panel udostępnia kontener, do którego można dodawać komponenty.

Tworzenie kontenera

Przed dodaniem komponentów tworzących interfejs użytkownika programista musi utworzyć kontener. Budując aplikację, programista musi najpierw utworzyć instancję klasy Window lub Frame. Podczas budowania apletu ramka (okno przeglądarki) już istnieje. Ponieważ klasa Applet jest podtypem klasy Panel, programista może dodawać komponenty do instancji samej klasy Applet.

Kod na liście 1 tworzy pustą ramkę. Tytuł ramki („Przykład 1”) jest ustawiany w wywołaniu konstruktora. Ramka jest początkowo niewidoczna i musi być widoczna, wywołując jej show()metodę.

import java.awt. *;

public class Example1 {public static void main (String [] args) {Frame f = new Frame ("Example 1");

f.show (); }}

Listing 1.

Pusta rama

Kod z listy 2 rozszerza kod z listy 1, dzięki czemu nowa klasa dziedziczy po klasie Panel. W main()metodzie instancja tej nowej klasy jest tworzona i dodawana do obiektu Frame poprzez wywołanie add()metody. Wynik jest następnie wyświetlany. Wyniki obu przykładów powinny wyglądać identycznie (to znaczy powinny wyglądać dość nieciekawie).

import java.awt. *;

public class Example1a extends Panel {public static void main (String [] args) {Frame f = new Frame ("Example 1a");

Przykład1a ex = nowy Przykład1a ();

f.add ("Center", ex);

f.pack (); f.show (); }}

Listing 2.

Ramka z pustym panelem

Dzięki wyprowadzeniu nowej klasy z klasy Applet zamiast z klasy Panel, ten przykład może teraz działać jako samodzielna aplikacja lub jako aplet osadzony na stronie sieci Web. Kod dla tego przykładu znajduje się na Listingu 3. Wynikowy aplet jest wyświetlany na Rysunku 5 (i nadal jest dość nieciekawy).

import java.awt. *;

public class Example1b extends java.applet.Applet {public static void main (String [] args) {Frame f = new Frame ("Example 1b");

Przykład1b ex = nowy Przykład1b ();

f.add ("Center", ex);

f.pack (); f.show (); }}

Listing 3.

Ramka z pustym apletem

Aby wyświetlić ten aplet, potrzebujesz przeglądarki obsługującej język Java.

Rycina 5.

Pusta rama

Uwaga: obiekt Window, aw niektórych przypadkach nawet obiekt Dialog, może zastąpić obiekt Frame. Wszystkie są prawidłowymi kontenerami, a komponenty są dodawane do każdego w ten sam sposób.

Dodawanie komponentów do kontenera

Aby interfejs użytkownika był użyteczny, musi składać się z czegoś więcej niż tylko kontenera - musi zawierać komponenty. Komponenty są dodawane do pojemników metodą kontenerową add(). Istnieją trzy podstawowe formy tej add()metody. Metoda użycia zależy od menedżera układu kontenera (patrz sekcja zatytułowana Układ komponentów ).

Kod z Listingu 4 dodaje utworzenie dwóch przycisków do kodu przedstawionego na Listingu 3. Tworzenie odbywa się w init()metodzie, ponieważ jest ona wywoływana automatycznie podczas inicjalizacji apletu. Dlatego bez względu na to, jak program jest uruchamiany, przyciski są tworzone, ponieważ init()są wywoływane przez przeglądarkę lub przez main()metodę. Rysunek 6 zawiera wynikowy aplet.

import java.awt. *;

public class Example3 extends java.applet.Applet {public void init () {add (new Button ("One")); dodaj (nowy przycisk ("Dwa")); }

public DimensionferredSize () {return new Dimension (200, 100); }

public static void main (String [] args) {Frame f = new Frame ("Przykład 3");

Przykład3 ex = nowy Przykład3 ();

ex.init ();

f.add ("Center", ex);

f.pack (); f.show (); }}

Listing 4.

Aplet z dwoma przyciskami

Aby wyświetlić ten aplet, potrzebujesz przeglądarki obsługującej język Java.

Rysunek 6.

Aplet z dwoma przyciskami

Układ komponentów

Do tej pory nie powiedziano nic o rozplanowaniu komponentów, które zostały dodane do pojemnika. Układ nie jest kontrolowany przez kontener, ale przez menedżera układu skojarzonego z kontenerem. Menedżer rozmieszczenia podejmuje wszystkie decyzje dotyczące rozmieszczenia komponentów. W AWT wszystkie klasy menedżera układu implementują interfejs LayoutManager.

AWT zapewnia pięciu menedżerów układu. Od bardzo prostych do bardzo złożonych. W tym artykule omówiono tylko dwie klasy menedżera układu używane w poniższych przykładach: klasę FlowLayout i klasę BorderLayout.

Klasa FlowLayout umieszcza komponenty w kontenerze od lewej do prawej. Gdy miejsce w jednym rzędzie zostanie wyczerpane, rozpoczyna się kolejny rząd. Do add()dodawania komponentów używana jest wersja jednoargumentowa metody kontenera .

Klasa BorderLayout ma pięć stref, jak pokazano na rysunku 7. Strefy są nazwane „Północ”, „Południe”, „Wschód”, „Zachód” i „Centrum”. W każdej z tych pięciu stref można umieścić jeden komponent. Po zmianie rozmiaru otaczającego kontenera wielkość każdej strefy granicznej jest zmieniana na tyle, aby pomieścić umieszczony w niej komponent. Nadmiar przestrzeni jest przeznaczony do strefy środkowej. Do add()dodawania komponentów używana jest dwuargumentowa wersja metody kontenera . Pierwszym argumentem jest obiekt String, który określa strefę, w której ma zostać umieszczony komponent.

Każda klasa kontenera ma domyślnego menedżera układu. Domyślnym menedżerem układu dla klasy Frame i klasy Dialog jest menedżer BorderLayout. Domyślnym menedżerem układu dla klasy Panel (i klasy Applet) jest menedżer FlowLayout.

Kod na liście 5 używa obu menedżerów układu i zawiera kilka dodatkowych składników interfejsu użytkownika. Wynik jest wyświetlany na rysunku 8.

import java.awt. *;

public class Example4 extends java.applet.Applet {public void init () {Panel p;

setLayout (nowy BorderLayout ());

p = nowy Panel ();

p.add (new TextArea ());

add ("Centrum", p);

p = nowy Panel ();

p.add (new Button („One”)); p.add (new Button ("Two"));

Wybór c = nowy Wybór ();

c.addItem ("jeden"); c.addItem ("dwa"); c.addItem ("trzy");

p.add (c);

add ("Południe", p); }

public static void main (String [] args) {Frame f = new Frame ("Przykład 4");

Przykład4 ex = nowy Przykład4 ();

ex.init ();

f.add ("Center", ex);

f.pack (); f.show (); }}

Listing 5.

Bardziej skomplikowany przykład

Aby wyświetlić ten aplet, potrzebujesz przeglądarki obsługującej język Java.

Cyfra 8.

Bardziej skomplikowany przykład

Obsługa zdarzeń

Powyższe przykłady nie robią nic poza wyświetlaniem obojętnego interfejsu użytkownika. Oczywiście bardzo ważne jest, aby interfejs użytkownika podejmował działania w wyniku działania użytkownika. Jednak głębsze zagłębianie się w tajemnice obsługi zdarzeń wykracza poza zakres tego artykułu. To musi poczekać do przyszłego artykułu. Jednak w celu zapewnienia kompletności przykładowy kod na liście 6 pokazuje, jak obsłużyć jeden typ zdarzenia, które może otrzymać program. Nowa klasa zastępuje action()metodę dostarczoną przez klasę Component. Do action()reaguje metodę do wydarzeń akcji, które są generowane na przykład poprzez wybór pozycji z listy pop-up. Plikaction()metoda wymaga podania dwóch parametrów, instancji Event i instancji Object. Instancja Event zawiera informacje o zdarzeniu, w tym o celu zdarzenia (komponencie, który jako pierwszy odebrał zdarzenie), współrzędnych x i y zdarzenia oraz czasie wystąpienia zdarzenia. Instancja Object przechowuje dane specyficzne dla zdarzenia. W przypadku obiektów Button zawiera tekst w etykiecie przycisku.

import java.awt. *;

klasa publiczna Example5 rozszerza java.applet.Applet {TextArea ta = null;

public void init () {Panel p;

setLayout (nowy BorderLayout ());

p = nowy Panel ();

ta = nowy TextArea ();

p.add (ta);

add ("Centrum", p);

p = nowy Panel ();

p.add (new Button („One”)); p.add (new Button ("Two"));

Wybór c = nowy Wybór ();

c.addItem ("jeden"); c.addItem ("dwa"); c.addItem ("trzy");

p.add (c);

add ("Południe", p); }

public boolean action (Event e, Object o) {String str = (String) o;

ta.appendText (str + "\ n");

return false; }

public static void main (String [] args) {Frame f = new Frame ("Przykład 5");

Przykład5 ex = nowy Przykład5 ();

ex.init ();

f.add ("Center", ex);

f.pack (); f.show (); }}

Listing 6.

Przykład z obsługą zdarzenia