Vorlesung 13. Sitzung Grundlegende Programmiertechniken Wintersemester 2007/2008 Dozent Nino Simunic M.A. Computerlinguistik, Campus DU Grundlegende Programmiertechniken, WS 2007/2008 GUI-Entwicklung mit Swing GUI–Programmierung mit Swing GUI: Schnittstelle zwischen Benutzer und Programm Beispiele? -3- Kommunikation mit Programm über Texteingabe, Knopfdruck, Regler-Manipulation, etc. Darstellung von Programm-Ergebnisse (nicht nur textuell) möglich. Word, Browser, Bildbetrachter, … Womit GUIs in Java programmieren? JFC (Java Foundation Classes). Bestehen im Kern aus den Teilen: -4- AWT, Swing 2D API, Accessability, Drag&Drop Wesentlichen Bestandteile/Aspekte einer GUI Fenster Layout Nehmen Container auf, welche wiederum weitere Container enthalten können. Anordnung von Steuerelementen und enthaltenen Containern via Layout Manager Graphische Benutzeroberfläche Eventhandling, (Ereignisverarbeitung) Verarbeitung von durch Quellen initiierte Ereignise (Knopfdruck, Reglermanipilation, …) -5- Steuerelemente Knöpfe, Regler, Dialoge als Quellen der Interaktion. Senden Ereignisse bei »Betätigung«. Illustration der Aspekte an einer Pseudo-GUI Ereignisverarbeitung Ereignis GUI Container Knopf Layout Kontroll-/Steuerelement, Ereignis-Quelle (Basis-)Fenster -6- Allgemeine Vorgehensweise bei der GUI-Entwicklung Spezifizierung des Designs und der Anordnung Spezifizierung der Benutzerinteraktionen Reaktionen auf Ereignisse? Erstellen des Basisfensters JFrame, JApplet, JDialog, … Hinzufügen der Elemente zum Container Hinzufügen der Container zum Basisfenster -7- Logisch zusammenhängende Elemente werden in einem Container zusammengefasst. Anordnung innerhalb eines Containers mit einem LayoutManager Mit Container ist die Subklasse von Component gemeint awt.Component Component bietet grundlegende Methoden Für die Darstellung von Komponenten am Bildschirm Vorbereitung der Komponente fr Benutzerinteraktionen Unterstützung für das Zeichnen, … awt.Component awt.2DGraphics awt.Window awt.Frame swing.JFrame -8- awt.Container swing.JComponent awt.Container Container: Subklassen von Component Ein Container ist eine Component, die Components aufnehmen kann Zwei Sorten von Containern: -9- Dient der Strukturierung des Oberfläche Stellt Methoden bereit, um Komponenten hinzuzufügen, zu positionieren, zu entfernen, zu gruppieren Komponenten werden als eine einzelne Einheit durch den Container zusammengefasst Top-Level Container Intermediate-level Container Top-Level Container Benutzeroberflächen in Java besitzen immer (mindestens) einen Top-Level-Container in der containment hierarchy (gleich) »Content Pane« (Inhaltsfläche) Swing Top-Level Container: JFrame, JDialog, JApplet Zweck: Darstellung der sichtbaren Komponenten Inhaltsflächen sind intermediate container Menüleiste: Nicht Teil der Inhaltsfläche Top-Level Container und Basisfenster Content Pane Menu Bar -1010- RootPane/LayeredPane fehlen in der vorliegenden Darstellung http://java.sun.com/docs/books/tutorial/uiswing/components/toplevel.html Komponenten hinzufügen: containment hierarchy To appear onscreen, every GUI component must be part of a containment hierarchy. A containment hierarchy is a tree of components that has a top-level container as its root.[1] Yellow Label -1111- [1] http://java.sun.com/docs/books/tutorial/uiswing/components/toplevel.html Mehrere Top-Level Container in einer GUI? […] A Swing-based GUI has at least one containment hierarchy with a JFrame as its root. For example, if an application has one main window and two dialogs, then the application has three containment hierarchies, and thus three top-level containers. One containment hierarchy has a JFrame as its root, and each of the other two has a JDialog object as its root.[1] M.a.W.: Immer nur ein Top-Level Container »ganz oben« in der Hierarchie. Weitere Komponenten müssen in einer dieser Hierarchien vorhanden sein. -1212- Ist das nicht der Fall, ist die Komponente schlichtweg nicht sichtund sinnvoll nutzbar. [1] http://java.sun.com/docs/books/tutorial/uiswing/components/toplevel.html Hinzufügen einer Komponente Zunächst: Sie fügen Komponenten nicht dem Basisfenster direkt hinzu, sondern der content pane (Inhaltsfläche) TLC haben eine standard Inhaltsfläche (engl. default content pane), welche dazu genutzt werden kann. -1313- Simpler intermediate container, erbt von Jcomponent, BorderLayout ist Layout Manager Default content pane erhält man via getContentPane Methode Hinzufügen einer Komponente: Beispielchen Der wesentliche Code zum Hinzufügen des »Yellow label« im letzten Beispiel: frame.getContentPane(). add(yellowLabel, BorderLayout.CENTER); frame ist der TLC (Hier ein JFrame-Objekt) void add(Component c) Container Methode. Wird an JFrame, JPanel,…, vererbet. Anweisung ist seit einigen Versionen identisch zu: frame.add(yellowLabel,BorderLayout.CENTER); -1414- Der restliche Quelltext: TopLevelDemo.java (ohne Menu) import java.awt.*; import javax.swing.*; public class TopLevelDemo { public static void main(String[] args) { //Create and set up the window. JFrame frame = new JFrame("TopLevelDemo"); frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); //Create a yellow label to put in the content pane. JLabel yellowLabel = new JLabel(); yellowLabel.setOpaque(true); // default: durchsichtig yellowLabel.setBackground(new java.awt.Color(248, 213, 131)); yellowLabel.setPreferredSize(new java.awt.Dimension(200, 180)); //Add label to top-level c. frame.getContentPane().add(yellowLabel, BorderLayout.CENTER); //Display the window. frame.pack(); frame.setVisible(true); } } -1515- Anmerkung zu getContentPane getContentPane return't ein Container Objekt, und kein JComponent Objekt. Folglich müssen Sie zu JComponent casten, um alle Features nutzen zu können. Auch möglich: Sie können die default content Pane durch eine eigene Komponente ersetzen (gleich). Das ersetzen geschieht via Methode setContentPane -1616- Einige wichtige Eigenschaften für Fenster: Wichtige Eigenschaften der Klasse Window Methoden void pack() Gibt dem Fenster die Größe, die zur Darstellung der enthaltenen Komponenten notwendig ist void dispose() Löscht das Fenster und gibt die belegten Resourcen frei awt.Component awt.Container awt.Window awt.Frame swing.JFrame -1717- swing.JComponent Wichtige Eigenschaften der Klasse JFrame Objekte der Klasse JFrame: frei bewegliche Fenster mit Rahmen und Titelleister Konstruktoren Methoden -1818- JFrame( ) JFrame(String title) void setTitle( String title ) String getTitle( ) void setSize( int x, int y ) void setLocation( int x, int y ) setVisible( boolean b ) setDefaultCloseOperation(int i) setDefaultCloseOperation(int i) Anstatt von int sind mehrsagendere Konstanten nützlich: javax.swing.WindowConstants.DISPOSE_ON_CLOSE Entspricht dem Wert 2 javax.swing.WindowConstants.HIDE_ON_CLOSE Enstpricht dem Wert 1 ... -1919- Default content pane austauschen (1) Sie wollen die default content pane Ihres TLC ersetzen. Bspw. eine Inhaltsfläche mit Rand und/oder eigenem Layout Manager Bspw. ein JPanel (Subklasse von JComponent) Theoretisch können Sie auch JButton verwenden, das macht aber als Inhaltsfläche eher weniger Sinn. Warum macht JPanel mehr Sinn? -2020- Klasse JPanel Einfachste Form eines Containers. Nichtsdestotrotz nützlich und typisch in Java-GUIs -2121- Subklasse von JComponent JPanel können weitere Container (JButton, JPanel, JSplitPane, …) hinzugefügt werden, ineinander verschachtelt werden, etc. Um ein Panel anzeigen zu können, muss es natürlich in einer containment hierarchy sein. Default content pane austauschen (2) Relevanter Code zur Erzeugung eines JPanel mit Rand und anderem Layout Manager: JPanel myContentPane = new JPanel(); myContentPane. setBorder(BorderFactory.createTitledBorder("MyPane")); myContentPane.setLayout(new java.awt.BorderLayout()); Nebenbei: Container haben standard-Layouts. JPanel's standard-Layout ist FlowLayout Das Ersetzen der Inhaltsfläche durch Ihre eigene: basisFenster.setContentPane(myContentPane); -2222- Das Beispiel im Programm import import import import javax.swing.BorderFactory; javax.swing.JFrame; javax.swing.JPanel; java.awt.BorderLayout; »Look&Feel« meines Betriebssystem. Aussehen kann demnach – je nach Umgebung – variieren. public class PaneTest { public static void main(String[] args) { JFrame basisFenster = new JFrame(); JPanel myContentPane = new JPanel(); myContentPane.setBorder(BorderFactory.createTitledBorder("MyPane")); myContentPane.setLayout(new BorderLayout()); basisFenster.setContentPane(myContentPane); basisFenster.setSize(100, 100); basisFenster.setVisible(true); Mit default content pane } (bspw. durch Weglassen des setContenPane } Aufrufs im Code): -2323- Layout und Layout Manager Layout von Elementen innerhalb eines Container werden via Layout Manager realisiert Das Content Pane eines Container wie Frame oder JFrame fragt bei einer Neudarstellung von seinen Elementen immer seinen Layoutmanager, wie er sie anordnen soll . Jeder Layout Manager implementiert eine unterschiedliche Strategie zur Anordnung. Bspw. -2424- Bspw. Buttons zentriert, oder von links nach rechts, … FlowLayout GridLayout BorderLayout, ... Verschiedene (Standard-)Layouts FlowLayout GridLayout Tabellarisch: Zeilen, Spalten new GridLayout(2,3) BorderLayout -2525- von links nach rechts, zentriert Richtungsangabe via Kompassrichtung someJFrame.add(new JButton("1"), BorderLayout.EAST); 1 2 3 1 2 3 4 5 6 NORTH WEST CENTER SOUTH 1 EAST GridTest.java import java.awt.GridLayout; import javax.swing.*; public class GridTest extends JFrame { GridTest(){ this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); JLabel lA = new JLabel("A"), lB = new JLabel("B"), lC = new JLabel("C"), lD = new JLabel("D"); GridLayout lay = new GridLayout(2,2); this.getContentPane().setLayout(lay); this.getContentPane().add(lA); this.getContentPane().add(lB); this.getContentPane().add(lC); this.getContentPane().add(lD); this.setSize(200,200); this.setVisible(true); } public static void main(String[] args) { new GridTest(); } -2626} Weitere Layouts (GridTest-Beispiel als Basis) GridLayout lay = new GridLayout(0,1); FlowLayout lay = new FlowLayout(FlowLayout.CENTER); GridLayout lay = new GridLayout(1,0); BorderLayout lay = new BorderLayout(10,10); this.getContentPane().setLayout(lay); this.getContentPane().add(lA, lay.WEST); this.getContentPane().add(lB, lay.EAST); this.getContentPane().add(lC, lay.NORTH); this.getContentPane().add(lD, lay.SOUTH); -2727- Steuerelemente Steuer- bzw. Kontrollelemente sind Entitäten der JComponent- Hierarchie Dienen der Ein-/Ausgabe von Daten über Bildschirm, Tastatur, Maus. I.d.R. aktive Elemente -2828- Bspw. JButtons, JLabels, JSlider, etc. Benutzer kann sie bspw. mit der Maus anklicken und dadurch ein Ereignis auslösen Ereignisbasierte Programmierung Konzepte ereignisbasierter Programmierung Senden und Empfangen der Ereignisse geschieht nach Auslösen der Aktion (fast) automatisch. Voraussetzung: -2929- Es gibt eine Ereignisquelle Die Ereignisquelle kann Ereignisse auslösen Es gibt einen Ereignisempfänger Der Empfänger muss die Quelle »kennen« Der Ereignisempfänger empfängt das Ereignis und führt entsprechende Aktionen durch Komponente muss Ereignisse versenden können Empfänger muss Ereignisse verarbeiten können Empfänger muss bei der Quelle registriert sein Illustration: Ereignisbasierte Programmierung, generisch Registrierung Ereignisquelle Ereignisempfänger Erzeugt Ereignis Behandelt Ereignis Benachrichtigung (notification ) -3030- Programmtechnische Umsetzung: Quelle, Ereignis, Empfänger Ereignisempfänger werden als Listener implementiert: Listener registriert sich bei der Quellkomponente Methode enthält die durchzuführenden Anweisungen Erwartet Objekt vom Typ Event als Argument Unterschiedliche Quellformen produzieren verschiedene Events und benötigen entsprechende Listener -3131- Komponente stellt Methode für die Registrierung zur Verfügung Auslösen einer Aktion führt zum Aufruf einer a priori zu implementierenden »Aktions-Methode« des Listeners Sind zu implementierende Interfaces aus java.awt.event.* Bsp. Knopfdruck: ActionEvent, ActionListener Event Klassen: Überblick -3232- Listener im Überblick -3333- Schrittweise Implementierung von Event-(Re-)Aktionen (1) (2) (3) -3434- Klasse, die auf das Event reagieren soll, implementiert das jeweilige Interfaces In Methode(-n) des Interface die Reaktion programmieren Listener-Objekt erzeugen und bei Instanz der Ereignisquelle registrieren Quelle benachrichtigt Empfänger immer, wenn Ereignis ausgelöst wird Implementierungsbeispiel GUI mit Knopf und Textfläche Knopfdruck bewirkt Textausgabe in der Textfläche -3535- Angabe, wie oft der Knopf gedrückt wurde Benötigt: Container/Steuerelemente, Layout, Listener-Implementierung und -Registrierung ButtonEventTest.java Listener class ButtonEventTest extends JFrame implements ActionListener { private JButton button1; private JTextPane jtp; private int butClicks; ButtonEventTest() { Ereignis-Quelle: /* Button, Textfläche erzeugen*/ button1 = new JButton("PUSH"); JButton jtp = new JTextPane(); jtp.setEditable(false); // nur lesen, nicht schreiben // Zur Inhaltsfläche hinzufügen getContentPane().add(button1, BorderLayout.NORTH); getContentPane().add(jtp, BorderLayout.CENTER); /* Listener registrieren */ Listener bei der Quelle button1.addActionListener(this); registrieren /* Eigenschaften des Fensters: */ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(new Dimension(100, 100)); setVisible(true); } public void actionPerformed(ActionEvent arg0) { jtp.setText("Gedrückt: "+butClicks++ ); } } } -3636- Reaktion auf das Ereignis. Obligatorisch zu implementierende Methode. Komponenten und Ereignisse JAbstractButton Action Event actionPeformed Change Event stateChanged Item Event itemStateChanged JTextComponent Caret Event caretUpdate JTextField Action Event actionPerfomed -3737- Zukünftiges (1) Die Testataufgabe kann ab Freitag, 15.02.2008, 15.00 Uhr, downgeloadet werden Bearbeitungszeit voraussichtlich 21 Tage Bei Verdacht auf Diebstahl bzw. Weitergabe geistigen Eigentums werden Teilnehmer zu Ihrer Testat-Lösung mündlich geprüft. Es wird erwartet, dass Sie sich in neue Themen einarbeiten »Neu«: Bislang ungesehene Klassen zur Datenstrukturierung (Collection-Framework), Generezität im Kontext Collections, GUIEntwicklung (Textfelder, Regler, …) Sie werden dazu nat. nützliche Literatur bzw. Literaturhinweise bekommen Alle relevanten Informationen (Bearbeitungszeit, Abgabemodalitäten, … ) zum angegebenen Zeitpunkt auf unserer Seite unter »Aktuelles«: http://www.uni-due.de/computerlinguistik/prog0708.shtml -3838- Zukünftiges (2) Es wird wieder Wiederholungstutorien geben. Vorläufige Termine sind kommenden Donnerstag (14.02.) und Freitag (15.02.), jeweils 3h. -3939- Die genauen Termine werden kommenden Montag auf »unserer« Seite bekanntgegeben. Voraussichtlich morgens (10.00-13.00) Teilnehmerzahlen sind jeweils beschränkt auf maximal 25 Personen! Sprechen Sie sich im Informatik-Forum bitte ab.