Java niezbędnik programisty spotkanie nr 12 Graficzny interfejs użytkownika 1
Graphical User Interface (GUI) Abstract Window Toolkit Swing słabo się prezentuje mało obiektowy projekt i implementacja zajęły miesiąc w wersji 1.1 wiele poprawiono i dodano JavaBeans jest oparty na JavaBeans i doskonale nadaje się do tworzenia interfejsu metodą przeciągnij-upuść nazewnictwo metod jest spójne i po zrozumieniu kilku przykładów do większości zastosowań wystarczy lektura dokumentacji w całości jest napisany w Javie (komponenty są uznawane za lekkie) "pluggable look and feel" można przełączać wygląd w zależności od systemu operacyjnego Standard Window Toolkit (SWT) konkurencyjna biblioteka IBM opracowana przy budowie Eclipse polega na komponentach GUI systemu operacyjnego 2
Applety Małe programiki uruchamiane wewnątrz przeglądarki internetowej Applety działają w piaskownicy izolacja od dysku twardego bezpieczeństwo dla użytkownika i mniejszy stres dla programisty Wszystko składające się na applet zazwyczaj musi być ściągane przy każdym uruchomieniu dobrym pomysłem jest zamknięcie wszystkiego w archiwum JAR archiwa JAR oraz poszczególne ich elementy można podpisywać elektronicznie koniec zamieszania z instalacją nowych wersji aplikacji 3
Zrąb Applety nie zawierają metody main() Typowa funkcjonalność zawarta jest w zrębie aplikacji (ang. application framework) Programista rozszerza klasy wchodzące w skład zrębu i przesłania odpowiednie metody Mechanizm sterowania wbudowany w zrąb odpowiada za wywoływanie tych metod w odpowiednim czasie To co niezmienne jest zakodowane w ramach zrębu 4
Cykl życia appletów init() - pierwsza wywoływana metoda, zawsze się ją przesłania, tu rozmieszczamy komponenty GUI destroy() - wywoływana, gdy applet już nie będzie potrzebny i należy zwolnić zasoby (np. jak strona na której się znajdował jest zamykana) stop() - wywoływana jak applet przestaje być widoczny (np. w wyniku przewinięcia strony), żeby wstrzymać zasobożerne obliczenia; wywoływana również tuż przed destroy() start() - wywoływana jak applet zaczął być widoczny, żeby wznowić normalne działanie; wywoływana również tuż przed init() import javax.swing.*; public class Applet1 extends JApplet { public void init() { getcontentpane().add(new Jlabel("Witaj Świecie!")); 5
Applet na stronie HTML Kiedyś wystarczał prosty znacznik <applet code=test12.applet1 width=100 height=50/> Ponieważ niektórzy producenci przeglądarek zaczęli go blokować, trzeba skorzystać ze standardowych mechanizmów wbudowanych w przeglądarkę, np. kontrolek ActiveX warto się posłużyć narzędziem HtmlConverter Applet można też uruchomić przy pomocy narzędzia appletviewer znacznik wskazujący applet podajemy wtedy w komentarzu import javax.swing.*; //<applet code=test12.applet1 width=100 height=50/> public class Applet1 extends JApplet { public void init() { getcontentpane().add(new JLabel("Applet!")); 6
Wygenerowany znacznik HTML <!--"CONVERTED_APPLET"--><!-- HTML CONVERTER --> <object classid = "clsid:8ad9c840-044e-11d1-b3e9-00805f499d93" codebase = "http://java.sun.com/update/1.5.0/jinstall-1_5-windowsi586.cab#version=5,0,0,5" WIDTH = 100 HEIGHT = 50/ > <PARAM NAME = CODE VALUE = test12.applet1 > <param name = "type" value = "application/x-java-applet;version=1.5"> <param name = "scriptable" value = "false"> <comment> <embed type = "application/x-java-applet;version=1.5" \ CODE = test12.applet1 \ WIDTH = 100 \ HEIGHT = 50/ scriptable = false pluginspage = "http://java.sun.com/products/plugin/index.html#download"> <noembed></noembed> </embed> </comment> </object> <!--<APPLET CODE = test12.applet1 WIDTH = 100 HEIGHT = 50/></APPLET>--> <!--"END_CONVERTED_APPLET"--> 7
Applet z metodą main public class Applet2 extends JApplet { public void init() { getcontentpane().add(new JLabel("Applet!")); public static void main(string[] args) { JApplet applet = new Applet2(); JFrame frame = new JFrame("Applet2"); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.getcontentpane().add(applet); frame.setsize(100,50); applet.init(); applet.start(); //warto jeszcze wywoływać stop() i destroy(), jak będzie za chwilę frame.setvisible(true); 8
Klasa pomocnicza public class Console { public static String title(object o) { String t = o.getclass().tostring(); if(t.indexof("class")!= -1) t = t.substring(6); return t; public static void run(japplet applet, int width, int height) { JFrame frame = new JFrame(title(applet)); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.getcontentpane().add(applet); frame.setsize(width, height); applet.init(); applet.start(); frame.setvisible(true); public static void run(jpanel panel, int width, int height) { JFrame frame = new JFrame(title(panel)); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.getcontentpane().add(panel); frame.setsize(width, height); frame.setvisible(true); 9
Dodajemy przycisk import javax.swing.*; import java.awt.*; public class Button1 extends JApplet { private JButton b1 = new JButton("Button 1"), b2 = new JButton("Button 2"); public void init() { Container cp = getcontentpane(); cp.setlayout(new FlowLayout());//domyślnie jest BorderLayout cp.add(b1); cp.add(b2); public static void main(string[] args) { Console.run(new Button1(), 200, 70); 10
Wzorzec Obserwator Komponenty GUI mogą generować wiele rodzajów zdarzeń Zajście poszczególnych zdarzeń może być interesujące dla wielu obiektów Obiekt zainteresowany danym zdarzeniem rejestruje się jako obserwator tego zdarzenia Gdy zdarzenie zajdzie obserwowany obiekt iteruje po liście zarejestrowanych obserwatorów i wywołuje podany przez nich kod Takie rozwiązanie obniża sprzężenie klas graficznego interfejsu użytkownika nie muszą być sprzężone ze wszystkimi klasami, które je obserwują a jedynie z przekazywaną przez nich klasą, na której wykonują wywołanie zwrotne 11
Przykład import javax.swing.*; import java.awt.event.*; import java.awt.*; public class Button2 extends JApplet { private JButton b1 = new JButton("Button 1"), b2 = new JButton("Button 2"); private JTextField txt = new JTextField(10); class ButtonListener implements ActionListener { public void actionperformed(actionevent e) { String name = ((JButton)e.getSource()).getText(); txt.settext(name); private ButtonListener bl = new ButtonListener(); public void init() { b1.addactionlistener(bl); b2.addactionlistener(bl); Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); cp.add(b1); cp.add(b2); cp.add(txt); public static void main(string[] args) { Console.run(new Button2(), 200, 100); 12
JTextArea public class TextArea extends JFrame { private Jbutton b = new JButton("Add Data"), c = new JButton("Clear Data"); private JTextArea t = new JTextArea(20, 40); private Map<String,String> m = new HashMap<String,String>(); public static void main(string[] args) { Console.run(new TextArea(), 475, 425);... 13
Przykład c.d. public TextArea() { b.addactionlistener(new ActionListener() { public void actionperformed(actionevent e) { Iterator it = m.entryset().iterator(); while(it.hasnext()) { Map.Entry me = (Map.Entry)(it.next()); t.append(me.getkey() + ": "+ me.getvalue()+"\n"); ); c.addactionlistener(new ActionListener() { public void actionperformed(actionevent e) { t.settext(""); ); Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); cp.add(new JScrollPane(t)); cp.add(b); cp.add(c); 14
Układ JApplet, JFrame, JWindow oraz JDialog po wywołaniu getcontentpane( ) zwracają obiekt klasy Container Kontener przechowuje i wyświetla komponenty. Przy pomocy setlayout( ) można zmienić sposób w jaki będą one układane Niektóre inne klasy jak JPanel przechowują i wyświetlają komponenty bezpośrednio i również bezpośrednio wywołujemy metodę setlayout( ) 15
BorderLayout Domyślny dla appletów import javax.swing.*; import java.awt.*; public class Layout1 extends JApplet { public void init() { Container cp = getcontentpane(); cp.add(borderlayout.north, new JButton("North")); cp.add(borderlayout.south, new JButton("South")); cp.add(borderlayout.east, new JButton("East")); cp.add(borderlayout.west, new JButton("West")); cp.add(borderlayout.center, new JButton("Center")); public static void main(string[] args) { Console.run(new Layout1(), 300, 250); 16
FlowLayout import javax.swing.*; import java.awt.*; public class Layout2 extends JApplet { public void init() { Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); for(int i = 0; i < 20; i++) cp.add(new JButton("Button " + i)); public static void main(string[] args) { Console.run(new Layout2(), 300, 250); wszystkie komponenty są upychane do najmniejszego możliwego dla nich rozmiaru np. dlatego wyrównanie tekstu do prawej na w JLabel nic nie zmieni, bo etykieta miała i tak rozmiar tekstu 17
Konstruowanie interfejsu metodą przeciągnij i upuść Opracował Największą kontrolę nad rozmieszczeniem dają GridBagLayout i (trochę prostrzy) BoxLayout Istnieje wiele narzędzi pozwalających tworzyć interfejs użytkownika metodą przeciągnij i upuść (np. Jbuilder) Ustawiając układ na null można podać bezwzględne pozycje i rozmiary komponentów. 18