PROGRAMOWANIE APLIKACJI MULTIMEDIALNYCH JĘZYK JAVA wykład 1 GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA Prowadzący: Tomasz Kowalski
Rozwój GUI w Java 2 Biblioteki GUI (Graphical User Interface) w Java 1 miały umożliwiać tworzenia interfejsu, który będzie wyglądał jednakowo na wielu platformach. Tego celu nie udało się osiągnąć. Abstract Window Toolkit (AWT) z Javy 1.0 tworzy GUI, które wygląda równie miernie na wszystkich systemach operacyjnych.
Rozwój GUI w Java 3 Dodatkowo narzucały ograniczenia: można było używać tylko czterech czcionek, nie można było uzyskać dostępu do bardziej wyszukanych elementów GUI, które istnieją w danym systemie operacyjnym, model programowania AWT jest niewygodny i niezorientowany obiektowo.
Rozwój GUI w Java 4 Poprawę przyniosło wprowadzenie AWT 1.1 do Javy 1.1 oraz standardu JavaBeans. Java 2 wprowadza JFC (Java Foundation Classes), którego część dotycząca GUI jest nazywana Swing. Jest to bogaty zbiór łatwych w użyciu i zrozumiałych komponentów JavaBeans, z których można w łatwy sposób tworzyć interfejs użytkownika.
Swing 5 Dostarcza komponenty umożliwiające tworzenie bogatych graficznych interfejsów użytkownika. Komponenty w Swingu definiowane są w klasach pakietu javax.swing. Ich nazwy zaczynają się literą J. Część komponentów to odpowiedniki komponentów z biblioteki AWT. Swing posiada również nowe komponenty nie dostępne w AWT.
Swing 6 Prawie wszystkie komponenty Swingu są komponentami lekkimi, co oznacza, że: mają taki sam wygląd niezależny od platformy systemowej (zależny wyłącznie od wybranego przez programistę stylu" look and feel), mogą być przezroczyste.
Hierarchia Swing 7 Jednak komponenty lekkie nie mogą istnieć bez jakiegoś komponentu ciężkiego. Taki komponent (choć jeden) musi znaleźć się na początku hierarchii zawierania się komponentów tak, aby komponenty lekkie mogły być na czymś rysowane.
Hierarchia Swing 8 Dlatego w Swingu kontenery najwyższego poziomu (okna i dialogi) zrealizowane są jako komponenty ciężkie (są to jedyne ciężkie komponenty Swingu). Okno ramowe, dialog i aplet pochodzą więc od odpowiednich klas AWT. Praca z kontenerami najwyższego poziomu (oknami) w Swingu zdecydowanie różni się od pracy z oknami w AWT ze względu na inną architekturę budowy tych komponentów.
9 Architektura okien Wszystkie wyżej wymienione typy okien zbudowane są z kilku części. Każde okno zawiera kontener root pane (typu JRootPane), który zawiera kontenery glass pane (szyba - obiekt typu JGlassPane) i layered pane (kontener warstwowy - obiekt typu JLayeredPane). Kontener layered pane zawiera content pane (kontener, do którego zwykle dodajemy komponenty) oraz ewentualnie pasek menu (JMenuBar).
Architektura okien 10
Rozmieszczenie komponentów wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 11 Sposób umieszczania komponentów na formatce w Javie różni się od innych powszechnie stosowanych systemów GUI: wszystko tutaj jest zapisane w kodzie, sposób ułożenia komponentów na formatce jest sterowany przez "menadżera ułożenia", menadżery ułożenia dostosowują wymiary do okna aplikacji.
12 Rozmieszczenie komponentów Komponenty JApplet, JFrame, JWindow i JDialog mogą zwrócić obiekt klasy Container (pojemnik). Służy do tego metoda getcontentpane(). Pojemnik ten może zawierać i wyświetlać komponenty (obiekty klas odziedziczonych z Component). W klasie Container dostępna jest metoda o nazwie setlayout(), która pozwala na wybranie jednego z menedżerów rozkładu.
Dodawanie komponentów import java.awt.container; import java.awt.flowlayout; import javax.swing.jbutton; import javax.swing.jframe; public class ButtonExample extends JFrame private JButton button1 = new JButton("Przycisk 1"); private JButton button2 = new JButton("Przycisk 2"); public ButtonExample() Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); cp.add(button1); cp.add(button2); settitle("buttonexample"); setsize(400, 300); public static void main(string[] args) new ButtonExample().setVisible(true); wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 13
Dodawanie komponentów wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 14
15 Rozkład BorderLayout Użyty bez dodatkowych parametrów powoduje, że komponenty zostaną umieszczone na środku obszaru i rozciągnięte aż do krawędzi. Wykorzystując przeciążoną metodę add() i stałe statyczne można układać komponenty geograficznie: BorderLayout.NORTH góra, BorderLayout.SOUTH dół, BorderLayout.EAST prawo, BorderLayout.WEST lewo, BorderLayout.CENTER środek.
Rozkład BorderLayout 16 Komponenty zmieniają rozmiary wraz ze zmianami rozmiaru kontenera: North i South w poziomie, ale nie w pionie, West i East w pionie, ale nie w poziomie, Center w obu kierunkach. Można dodatkowo podać odstępy między komponentami (pion, poziom): new BorderLayout(int, int);
17 import java.awt.borderlayout; import java.awt.container; Rozkład BorderLayout import javax.swing.*; public class BorderLayoutExample extends JFrame public BorderLayoutExample() Container cp = getcontentpane(); cp.add(borderlayout.north, new JButton("Północ")); cp.add(borderlayout.south, new JButton("Południe")); cp.add(borderlayout.east, new JButton("Wschód")); cp.add(borderlayout.west, new JButton("Zachód")); cp.add(borderlayout.center, new JButton("Środek")); settitle("borderlayoutexample"); setsize(400, 400); public static void main(string[] args) new BorderLayoutExample().setVisible(true);
Rozkład BorderLayout 18
Rozkład FlowLayout 19 Komponenty ułożone są w wierszu. Przy zmianie rozmiarów kontenera rozmiary komponentów nie zmienią się. Jeśli szerokość kontenera jest za mała, pojawiają się dodatkowe wiersze.
Rozkład FlowLayout Stałe statyczne FlowLayout.LEFT, FlowLayout.CENTER, FlowLayout.RIGHT pozwalają ustalić jak mają być wyrównane komponenty. Można ustalić odstępy (w pionie i poziomie) między komponentami. wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 20
21 import java.awt.container; import java.awt.dimension; import java.awt.flowlayout; Rozkład BorderLayout import javax.swing.jbutton; import javax.swing.jframe; public class FlowLayoutExample extends JFrame public FlowLayoutExample() Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); for(int i = 0; i < 20; i++) cp.add(new JButton("Przycisk " + i)); settitle("flowlayoutexample"); setsize(new Dimension(500, 200)); public static void main(string[] args) new FlowLayoutExample().setVisible(true);
Rozkład BorderLayout 22
Rozkład GridLayout 23 Rozkłada komponenty na regularnej siatce (tablicy). Rozmiary wszystkich komponentów są takie same. Zmieniają się wraz ze zmianami rozmiaru kontenera. W konstruktorze można podać liczbę wierszy i kolumn, które będą rozmieszczone równomiernie na obszarze kontenera.
24 import java.awt.container; import java.awt.gridlayout; Rozkład GridLayout import javax.swing.jbutton; import javax.swing.jframe; public class GridLayoutExample extends JFrame public GridLayoutExample() Container cp = getcontentpane(); cp.setlayout(new GridLayout(7, 3)); for(int i = 0; i < 20; i++) cp.add(new JButton("Przycisk " + i)); settitle("gridlayoutexample"); pack(); public static void main(string[] args) new GridLayoutExample().setVisible(true);
Rozkład GridLayout 25
Rozkład GridBagLayout wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 26 Dostarcza ogromnych możliwości kontroli nad ułożeniem komponentów. Jednak jest to też najbardziej skomplikowany menedżer układu trudny do zrozumienia. Przeznaczony jest głównie do automatycznego generowania kodu przez wizualne narzędzia tworzenia interfejsu.
27 Rozkład BoxLayout Posiadająca wiele zalet GridBagLayout, ale nie tak skomplikowany. Można go więc częściej stosować, gdy trzeba ręcznie zakodować układ Pozwala na kontrolę rozmieszczenia komponentów w pionie lub w poziomie oraz na kontrolę odstępów pomiędzy komponentami. W rozkładzie tym stosuje się coś nazwanego rozdzielaczami i klejem.
28 Rozkład BoxLayout Konstruktor klasy BoxLayout różni się trochę od konstruktorów pozostałych menedżerów. Jego pierwszy argument to pojemnik, który będzie kontrolowany przez BoxLayout, a drugi argument to kierunek układania.
29 Rozkład BoxLayout Aby istniejącemu kontenerowi cont nadać rozkład BoxLayout: pionowy: cont.setlayout( new BoxLayout( cont, BoxLayout.Y_AXIS); poziomy: cont.setlayout( new BoxLayout( cont, BoxLayout.X_AXIS);
import java.awt.*; import javax.swing.*; Rozkład BoxLayout public class BoxLayoutExample extends JFrame public BoxLayoutExample() JPanel vertical = new JPanel(); vertical.setlayout(new BoxLayout(vertical, BoxLayout.Y_AXIS)); for(int i = 0; i < 5; i++) vertical.add(new JButton("vertical: " + i)); JPanel horizontal = new JPanel(); horizontal.setlayout(new BoxLayout(horizontal, BoxLayout.X_AXIS)); for(int i = 0; i < 5; i++) horizontal.add(new JButton("horizontal: " + i)); Container cp = getcontentpane(); cp.add(borderlayout.east, vertical); cp.add(borderlayout.south, horizontal); settitle("boxlayoutexample"); pack(); public static void main(string[] args) new BoxLayoutExample().setVisible(true); wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 30
Rozkład BoxLayout 31
32 Rozkład BoxLayout W przypadku tworzenia nowego kontenera można użyć klasy Box, która definiuje kontener lekki o rozkładzie BoxLayout (Box nie jest J- komponentem!). Tworzenie obiektu Box: za pomocą konstruktora Box(int), gdzie argument to BoxLayout.X_AXIS lub Y_AXIS, za pomocą statycznych metod zwracających referencję do utworzonego obiektu Box: Box.createHorizontalBox(), Box.createVerticalBox().
import java.awt.*; import javax.swing.*; Rozkład BoxLayout public class BoxExample extends JFrame public BoxExample() Box vertical = Box.createVerticalBox(); for(int i = 0; i < 5; i++) vertical.add(new JButton("vertical: " + i)); Box horizontal = Box.createHorizontalBox(); for(int i = 0; i < 5; i++) horizontal.add(new JButton("horizontal: " + i)); Container cp = getcontentpane(); cp.add(borderlayout.east, vertical); cp.add(borderlayout.south, horizontal); settitle("boxexample"); pack(); public static void main(string[] args) new BoxExample().setVisible(true); wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 33
Rozkład BoxLayout 34
35 Rozkład BoxLayout W klasie Box zdefiniowano też wygodne metody statyczne do wprowadzania wypełniaczy" przestrzeni w rozkładzie BoxLayout. Te wypełniacze noszą nazwy rozdzielacz (strut) i klej (glue). Rozdzielacze odsuwają komponenty na ustaloną odległość. Sklejenie oddziela komponenty na tyle, na ile jest to możliwe zatem jest to bardziej sprężyna niż klej. Rozdzielacze działają w jednym kierunku, natomiast sztywny obszar ustawia odstępy między komponentami w obydwu kierunkach.
Rozkład BoxLayout import java.awt.*; import javax.swing.*; public class AnotherBoxExample extends JFrame public AnotherBoxExample() Box vertical = Box.createVerticalBox(); for(int i = 0; i < 5; i++) vertical.add(new JButton("vertical: " + i)); vertical.add(box.createverticalstrut(i * 10)); Box horizontal = Box.createHorizontalBox(); for(int i = 0; i < 5; i++) horizontal.add(new JButton("horizontal: " + i)); horizontal.add(box.createhorizontalstrut(i * 10)); Container cp = getcontentpane(); cp.add(borderlayout.east, vertical); cp.add(borderlayout.south, horizontal); settitle("anotherboxexample"); pack(); public static void main(string[] args) new AnotherBoxExample().setVisible(true); wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 36
Rozkład BoxLayout 37
import java.awt.*; import javax.swing.*; Rozkład BoxLayout public class YetAnotherBoxExample extends JFrame public YetAnotherBoxExample() Box vertical = Box.createVerticalBox(); vertical.add(new JButton("Przycisk 1")); vertical.add(box.createverticalglue()); vertical.add(new JButton("Przycisk 2")); vertical.add(box.createverticalglue()); vertical.add(new JButton("Przycisk 3")); Box horizontal = Box.createHorizontalBox(); horizontal.add(new JButton("Przycisk 4")); horizontal.add(box.createhorizontalglue()); horizontal.add(new JButton("Przycisk 4")); horizontal.add(box.createhorizontalglue()); horizontal.add(new JButton("Przycisk 5")); vertical.add(box.createverticalglue()); vertical.add(horizontal); vertical.add(box.createverticalglue()); getcontentpane().add(vertical); pack(); settitle("yetanotherboxexample"); public static void main(string[] args) new YetAnotherBoxExample().setVisible(true); wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 38
Rozkład BoxLayout 39
Rozkład BoxLayout 40 import java.awt.*; import javax.swing.*; public class TheLastBoxExample extends JFrame public TheLastBoxExample() Box vertical = Box.createVerticalBox(); vertical.add(new JButton("Góra")); vertical.add(box.createrigidarea(new Dimension(120, 90))); vertical.add(new JButton("Dół")); Box horizontal = Box.createHorizontalBox(); horizontal.add(new JButton("Lewo")); horizontal.add(box.createrigidarea(new Dimension(160, 80))); horizontal.add(new JButton("Prawo")); vertical.add(horizontal); getcontentpane().add(vertical); pack(); settitle("thelastboxexample"); public static void main(string[] args) new TheLastBoxExample().setVisible(true);
Rozkład BoxLayout 41
Bezpośrednie pozycjonowanie wykład 1: GUI GRAFICZNY INTERFEJS UŻYTKOWNIKA 42 Możliwe jest również bezpośrednie ustawienie pozycji komponentów graficznych. Można to zrobić w następujący sposób: usuń menedżer układu dla danego obiektu <Container>.setLayout(null), dla każdego komponentu wywołaj setbounds(), przekazując prostokąt ograniczający opisany w pikselach.
Najlepszy wybór 43 W rzeczywistości można wiele osiągnąć, łącząc proste układy. Jednak od pewnego momentu ręczne rozmieszczanie komponentów staje się zbyt skomplikowane i pracochłonne. Projektanci Javy i Swinga ukierunkowali język i biblioteki tak, by wspomagały narzędzia do wizualnego tworzenia GUI. Jeśli programista rozumie, co się dzieje z menedżerem układu, to nie jest szczególnie ważne, czy wie, jak ułożyć komponenty ręcznie. Równie dobrze może to zrobić za nas odpowiednie narzędzie.