Oberflächenprogrammierung mit Swing
Oberflächenprogrammierung mit SwingGrafische Benutzeroberflächen in Java
- GUI: englische Abkürzung für "Graphical User Interface" oft auch mit UI (User Interface) abgekürzt
- Ziel graphischer Benutzeroberflächen:
- Intuitiv bedienbare Benutzerschnittstellen für ungeübte Benutzer
- Optionen zu effizienten Benutzung von erfahrenen Benutzern (Kommandos auf Befehlstasten, Tabulatoren zum Bewegen zwischen Eingabefeldern etc.)
- Vorteil von Java-GUIs
- Plattformunabhängigkeit (write once, run anywhere)
- 7453 views
Entwicklungsgeschichte der grafischen Benutzerschnittstellen in Java (JRE)
Entwicklungsgeschichte der grafischen Benutzerschnittstellen in Java (JRE)Swing ist das Ergebnis einer Evolution der grafischen Benutzerschnittstellen die seit 1996 immer weiterentwickelt wurden. Der geschichtliche Überblick ist hilfreich beim Verstehen der recht komplexen Paketstrukturen von Swing und AWT.
Java 1.0: Another Windowing Toolkit (AWT)
- Jahr 1996
- Paket: java.awt.*
Die ursprüngliche Grafikbibliothek AWT sollte die folgenden Anforderungen erfüllen
- einfach zu verstehen und zu Programmieren ("Volks GUI")
- weniger komplex als das damals populäre X11, Motif von Unix-Workstations
- unabhängig von Windows (Rechte, Lizensen!)
- Kleine Teilmenge der wichtigsten GUI Elemente
- geplanter Einsatz Browser-Applets und TV-Settop Boxen (Auf Neudeutsch "Kabeltuner")
- Internet Browser zu mehr Interaktion und mehr Intelligenz zu verhelfen
- leicht auf unterschiedlichen Betriebssytemen zu implementieren
AWT hat daher die folgenden Eigenschaften
- nur wenige GUI Komponenten
- HeavyWeight Implementierung (direkte Abbildung auf Betriebssystemkomponenten)
- Threadsicher
- keine Model-View-Controller Architektur
Java 1.1: AWT + Java Foundation Classes (JFC)
- Jahr 1997
- Paket: javax.swing.*
Das AWT musste um eine objektorientierte Ereignissteuerung erweitert werden da das Implementieren von GUIs mit vielen Komponenten sehr unübersichtich war
Gleichzeitig wurde ein vollkommenes Neudesign mit einem optionalen Package (javax Pakete) mit dem Projektnamen Swing (engl. Schaukel) vorgestellt. Der offizielle Name war "Java Foundation Classes".
Da JFC zum Zugriff auf die Betriebssytemkomponenten AWT benutzen muss, ist es von AWT abhängig. JFC ist eine "light weight" Implementierung und daher stärker vom gegebenen Betriebssytemen entkoppelt.
Java 1.2: JFC/Swing Standard GUI
JFC (Swing) muss nicht mehr separat geladen werden und ist Bestandteil des Standard JREs. Es verdrängt AWT mehr und mehr. Seine wichtigsten Eigenschaften sind
Swing wurde seit JRE 1.2 kontinuierlich weiterentwickelt und erhielt in jeder neuen JRE Version zusätzliche Eigenschaften. Die Demoanwendung SwingSet2 ist eine gute Referenzanwendung in der sehr viele Komponenten verwendet werden. |
"Lightweight" versus "Heavyweight" Implementierungen
Man spricht von Heavyweight Komponenten wenn zu ihrer Implementierung die vom Betriebssytem zu Verfügung gestellten Komponenten verwendet werden.
In einer Heavyweight Implementierung wird z.Bsp. zur Anzeige einer Menüauswahliste direkt die Menüauswahlliste des Betriebssytem verwendet.
Man spricht von einer Lightweight Implementierung wenn eine Grafikbibliothek vom Betriebsystem nur einen Pixelbereich auf dem Bildschirm nutzt und dann die Komponenten selbst zeichnet (rendered). Bei einer Lightweigtimplemenierung muss die Anwendung zum Beispiel eine Menüauswahlliste selbst auf dem Bildschirm zeichnen und selbst darauf achten, welche Bereiche des Fenster überschrieben werden.
Vorteile | Nachteile | |
---|---|---|
Heavyweight |
|
|
Lightweight |
|
|
Anmerkung: Die historischen (vor 2005) Probleme von Swing sind in den aktuellen Javaversion nicht mehr vorhanden. Moderne Garbage-Kollektoren blockieren die Benutzerschnittstellen nicht mehr sichtbar. Die aktuelle 2D Bibliothek von Java zeichnet in der Regel ausreichend schnell und benutzt auf den gängigen Plattformen (Windows, Mac, Linux) die Betriebssystemoptimierungen für Fonts, 2D- und 3D-Operationen. JavaFX stellt auch die nötigen hardwareunterstützten Operationen für Bildtransformationen und Filme zur Verfügung.
- 6142 views
Implementieren von einfachen Swingkomponenten
Implementieren von einfachen SwingkomponentenSwing-Komponenten
Eine sehr anschauliche Übersicht über die existierenden Swing-Komponenten kann man auf der Seite des MIT finden. Hier gibt es auch Beispielcode. Bei Oracle kann man auch ein Tutorial mit Beispielcode finden.
Komponente (In Java Swing) |
---|
Komponenten sind grafische Bereiche die mit dem Benutzer interagieren können. |
Toplevel Container
Swing verfügt über drei "Top-level-Container" in denen Benutzeroberflächen implementiert werden können:
- JFrame: reguläre freistehende Programmfenster mit (optionaler) Menüleiste
- JDialog: Eine Dialog-Box für modale Dialoge wie z.Bsp. Fehlermeldungen
- JWindow: Ein freistehendes Fenster ohne Menüleisten, ohne Buttons zur Verwaltung des Fensters
Container (In Java Swing) |
---|
Ein Container ist eine Komponente die andere AWT Kompomenten enthalten kann. |
Fenster: Klasse JFrame
Fenster können mit der Klasse JFrame erzeugt werden. Das folgende Beispielprogramm erzeugt ein einfaches Fenster der Größe 300 Pixel x 100 Pixel mit einem Titel in der Kopfleiste:
package s2.swing; import javax.swing.JFrame; public class JFrameTest { public static void main(String[] args) { JFrame myFrame = new JFrame("Einfaches Fenster"); myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Beende Anwendung bei Schließen des Fensters myFrame.setSize(300,100); // Fenstergroesse 300x100 Pixel myFrame.setVisible(true); // Mache Fenster sichtbar } }
Erzeugt das folgende Fenster (MacOS):
Die Klasse JFrame erbt die Eigenschaften von Component, Container, Window und Frame aus dem AWT Paket:
Die vollständge Beschreibung findet man in der Java API Dokumentation.
Ein JFrame besteht aus mehreren Ebenen in denen unterschiedliche grafische Objekt positioniert sind:
Die Verwendung der unterschiedlichen Ebenen ist ein fortgeschrittenes Thema und wird im Rahmen des Kurses nicht behandelt. Es ist jedoch wichtig zu wissen, dass diese verschiedenen Ebenen existieren. Das Glass ane erlaubt beispielsweise eine unsichtbare Struktur über das GUI zu legen und damit zum Beispiel Mausereignisse abzufangen. Mehr Informationen sind z. Bsp. in der Oracle Dokumentation zu finden.
Buttons: Die Klasse JButton
Buttons können leicht mit der Klasse JButton erzeugt werden. Sie können mit der add() Methode dem Fenster hinzugefügt werden da das JFrame als Container in der Lage ist Komponenten aufzunehmen.
Beispiel: JButton in einem JFrame
package s2.swing; import javax.swing.JButton; import javax.swing.JFrame; public class JFrameButtonTest { public static void main(String[] args) { JFrame myFrame = new JFrame("Einfaches Fenster"); myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); myFrame.add(new JButton("Click mich ich bin ein JButton!")); myFrame.setSize(300,100); myFrame.setVisible(true); } }
Ergibt das folgende Fenster:
Swing bietet eine Reihe von Varianten von Buttons an auch in Menüleisten verwendet werden können. Die entsprechenden Klassen werden von der Klasse AbstractButton abgeleitet:
Textfelder: Klasse JTextComponent und JTextField
Swing erlaubt die Verwaltung von Eingabetextfeldern durch die Klasse JTextField. Die Klasse JTextField ist die einfachste Möglichkeit Text auszugeben und einzugeben wie im folgenden Beispiel zu sehen ist.
Beispiel: JTextfield in JFrame
package s2.swing; import javax.swing.JFrame; import javax.swing.JTextField; public class TextfeldTest { public static void main(String[] args) { JFrame frame = new JFrame("Ein Fenster mit Textfeld"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JTextField("Editier mich. Ich bin ein JTexfield", 60)); frame.setSize(300, 100); frame.setVisible(true); } }
Das Programm erzeugt bei der Ausführung das folgende Fenster:
Beispiel: JTextField in einem Applet/Hauptprogramm
Swing bietet eine ganze Reihe von Möglichkeiten mit Texten umzugehen wie sich aus der Klassenhierarchie von JTtextComponent ergibt:
Beschriftungen: Klasse JLabel
Einfache, feste Texte für Beschriftungen werden in Swing mit der Klasse JLabel implementiert:
package s2.swing;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
*
* @author s@scalingbits.com
*/
public class JLabelTest {
public static void main(String[] args) {
JFrame f = new JFrame("Das Fenster zur Welt!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JLabel("Hinweistext!"));
f.setSize(100, 80);
f.setVisible(true);
}
}
Das Programm erzeugt bei der Ausführung das folgende Fenster:
Container, Behälter für andere Komponenten: Klasse JPanel
Zum Anordnen und Positionieren von Komponenten wird die Klasse JPanel verwendet. Sie ist ein Behälter der andere Komponenten aus der JComponent-Hierarchie verwalten kann. Dies sind z.Bsp.:
- andere JPanels
- JButton
- JTextField
- JLabel etc.
JPanels haben zwei weitere wichtige Eigenschaften
- sie können nur ihren eigenen Hintergrund zeichnen
- sie benutzen Layoutmanager um die Positionierung der JComponenten durchzuführen
Jede Instanz eines JPanels hat einen eigenen Layoutmanager. Da typischerweise ein Layoutmanager nicht ausreicht, werden JPanels und deren Layoutmanager geschachtelt.
Beispiel: JTextfield in JFrame
import javax.swing.JFrame; import javax.swing.JTextField; /** * * @author s@scalingbits.com */ public class TextfeldTest { public static void main(String[] args) { JFrame frame = new JFrame("Ein Fenster mit Textfeld"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JTextField("Editier mich. Ich bin ein JTextfield", 60)); frame.setSize(300, 100); frame.setVisible(true); } }
Das Programm erzeugt bei der Ausführung das folgende Fenster:
Beispiel: JTextField in einem Applet
Quellcode |
---|
package s2.swing; import java.awt.BorderLayout; /** public JPanelJApplet() { JButton myButton = new JButton("Click mich"); JLabel myLabel = new JLabel("Ich bin ein JLabel"); JPanel myPanel = new JPanel(); Container myPane = getContentPane(); @Override |
- 8575 views
Top Level Container
Moin Moin,
in ihrem Skript steht etwas von "3 Top-Level Container", aufgezählt sind aber 4.
Also wie viele sind es?
Anmerkung: Hinter "JApplet" steht ein Semikolon und kein Doppelpunkt. Und es fehlt ein "p" bei pain, bei "JFrame" ganz am Ende im letzten Absatz.
Gruß
- Log in to post comments
Gut beobachtet
Applets werden von keinen gängigen Browsern aus Sicherheitsgründen mehr unterstützt. Da man mit Applet nichts mehr machen kann bleiben noch drei. Habe das Skript angepasst.
- Log in to post comments
Layoutmanager
LayoutmanagerLayoutmanager erlauben die Anordnung von Komponenten in einem Container. Abhängig vom gewählten Manager werden die Komponenten in ihrer gewünschten oder in einer gestreckten, bzw. gestauchten Form angezeigt. Die Feinheiten der Layout-Manager werden hier nicht behandelt. Es werden auch nur die wichtigsten Layout-Manager vorgestellt. Die Swingdokumentation ist für die Entwicklung von GUIs unerlässlich.
Definition: Layout-Manager |
---|
Ein Layout-Manager ist ein Objekt, welches Methoden bereitstellt, um die grafische Repräsentation verschiedener Komponenten innerhalb eines Container-Objektes anzuordnen |
Wichtig: Eine absolute Positionierung von Komponenten ist ungünstig, da Fenster eine unterschiedliche Größe haben können.
Java biete eine Reihe von Layout-Managern. Im Folgenden wird eine Auswahl vorgestellt:
Flowlayout
Das FlowLayout ist das einfachste und Standardlayout. Es wird benutzt wenn kein anderer Layoutmanager angeben wird. In ihm werden die Komponenten in der Reihenfolge des Einfügens von links nach rechts eingefügt.
Strategie: Alle Komponenten werden in einer Reihe wie in einem Fließtext angeordnet. Reicht die gegebene Breite nicht erfolgt ein Umbruch mit einer neuen Zeile.
Dem JPanel jp wird im Folgenden kein expliziter LayoutManager mitgegeben um die 6 Knöpfe zu verwalten es wird der FlowLayoutmanager als Standardeinstellung verwendet:
package s2.swing; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; /** * Zeigt einen sehr einfachen FlowlayoutManager mit 5 Buttons * @author s@scalingbits.com */ public class FlowlayoutTest { /** * Hauptmethode * @param args Es werden keine Parameter ausgewertet */ public static void main(String[] args) { JFrame f = new JFrame("FlowLayout"); JPanel jp = new JPanel(); for (char c = 0; c <= 5; ++c) { // Stecke 6 Buttons in das Panel jp.add(new JButton("Button " + (char)('A'+c))); } f.add(jp); // Füge Panel zu Frame //Beende Anwendung beim Schliesen des Fensters f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); // Berechne Layout f.setVisible(true);// Zeige alles an } }
Ergibt ein Fenster mit dem folgenden Layout:
Bei mangelndem horizontalem Platz wird ein automatischer Umbruch in eine neue Zeile durchgeführt (siehe rechts). |
Eigenschaften Flowlayout
- Komponenten behalten ihre Wunschgröße
- Zeilenumbruch bei mangelndem horizontalen Platz
- aus den beiden ersten Eigenschaften ergibt sich, dass Komponenten eventuell nur teilweise angezeigt werden oder völlig verdeckt sein können!
Borderlayout
Der Borderlayoutmanager erlaubt das Gruppieren von Komponenten abhängig von der Richtung im Panel.
Strategie: Die zur Verfügung stehende Fläche wird in fünf Bereiche nach den Himmelsrichtungen aufgeteilt
- NORTH (Oben)
- SOUTH (Unten)
- EAST (Rechts)
- WEST (Links)
- CENTER (Mitte)
Der Centerbereich ist der priorisierte Bereich.
Das BorderLayout ist die Standardeinstellung für die Klassen Window und JFrame.
Im nächsten Beispiel wir je ein Knopf (Button) in einem der Bereiche angelegt:
}
Zur Bestimmung der Position werden Konstanten mit den englischen Namen der Himmelsrichtung verwendet (Bsp. BorderLayout.NORTH). Beim Borderlayout ist zu beachten, dass Komponenten die oben, bzw. unten angeordnet werden über die ganze Breite des Containers gezeichnet werden. Komponenten die links und rechts angeordnet werden sind jedoch immer unter, bzw. über den Komponenten die oben und unten angelegt urden.
Eigenschaften BorderlayoutSiehe Fenster rechts mit größerem Fensterbereich:
|
BoxLayout
Das BoxLayout erlaubt das Anordnen von Komponenten in Zeilen oder Spalten. Durch das Verschachteln von BoxLayoutmanagern kann man ähnliche Effekte wie beim GridLayout erzielen. Man hat jedoch die Möglichkeit einzelne Zeilen oder Spalten individuell zu konfigurieren.
Das BoxLayout versucht alle Komponenten mit ihrer bevorzugten Breite bei der horizontalen Darstellung zu positionieren. Die Höhe aller Komponenten wird hier versucht auf Die Wunschhöhe der höchsten Komponente wird benutzt um die Gesamthöhe zubestimmen.
Bei der vertikalen Darstellung wird entsprechend versucht die bevorzugte Höhe zu verwenden. Bei der vertikalen Darstellung versucht der Layoutmanager alle Komponenten horizontal so weit wie die breiteste Komponente zu strecken.
Komponenten können aneinander
- Linksbündig
- Rechtsbündig
- Zentriert
ausgerichtet werden
Das folgende Beispiel zeigt ein horizontales Boxlayout welches nach 2 Sekunden automatisch die Orientierung zu vertikal und dann wieder zurück triggert:
package s2.swing;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class BoxLayoutTest {
public static void main(String[] args) {
int wartezeit = 2000; // in Millisekunden
JFrame f = new JFrame("BoxLayout");
JPanel jp = new JPanel();
// Erzeuge ein horizontales und ein vertikales BoxLayout
BoxLayout horizontal = new BoxLayout(jp, BoxLayout.X_AXIS);
BoxLayout vertikal = new BoxLayout(jp, BoxLayout.Y_AXIS);
jp.setLayout(horizontal);
for (char c = 0; c < 4; ++c) {
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true); // Warte 2 Sekunden try { Thread.sleep(wartezeit); // Wechsle fünfmal die Orientierung alle zwei Sekunden for (int i = 0; i < 5; i++) { jp.setLayout(vertikal); f.setTitle("BoxLayout - Vertikal"); f.pack(); Thread.sleep(wartezeit); jp.setLayout(horizontal); f.setTitle("BoxLayout - Horizontal"); f.pack(); Thread.sleep(wartezeit); } } catch (InterruptedException e) { // Mache nichts im Fall einer Ausnahme } } }
Ein horizontales Layout wird mit der Konstanten BoxLayout.X_AXIS beim Konfigurieren des Layoutmanagers erzeugt:
Ein vertikales Layout wird beim Erzeugen des Layoutmanagers mit Hilfe der Konstanten BoxLayout.Y_AXIS konfiguriert:
Eigenschaften Boxlayout
- Jede Komponente wird in ihrer Wunschgröße dargestellt
- Die Größe des Containers ergibt sich aus der größten Wunschhöhe und der größten Wunschbreite
Hinweis: Die zweizeilige JTextArea im Beispiel oben hat eine andere Wunschgröße als die Knöpfe
GridLayout
Der GridLayoutmanager erlaubt die Anordnung von Komponenten in einem rechteckigen Raster (Grid: engl. Raster, Gitter). Der Gridlayoutmanager versucht die Komponenten von links nach rechts und von oben nach unten in das Raster einzufügen.
Strategie: Alle Zellen haben eine einheitliche Größe
Wird für die Größe der Zeilen oder Spalten eine 0 angegeben erlaubt dies das Anlegen beliebig vieler Element in den Spalten oder Zeilen.
Im folgenden Beispiel werden 11 Buttons und ein Textfeld in drei Reihen und vier Spalten angeordnet: package s2.swing;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class GridLayoutTest {
public static void main(String[] args) {
JFrame f = new JFrame("GridLayout");
JPanel jp = new JPanel();
jp.setLayout(new GridLayout(3,4));
for (char c = 0; c < 11; ++c) {
jp.add(new JButton("Button " + (char)('A'+c)));
}
JTextArea jta =new JTextArea(3,10);
jta.append("JTextArea \nsecond row\nthird row");
jp.add(jta);
f.add(jp);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
|
Dies ergibt das folgende Fenster bei der Ausführung: |
Eigenschaften des Gridlayouts
|
gestauchtes Fenster: |
- 8749 views
Boxlayout - Schreibfehler
Hallo,
"Das folgende Beispiel zeigt ein vertikales Boxlayout welches nach 2 Sekunden automatisch die Orientierung zu vertikal und zurück triggert:"
-> Müsste sicher "die Orientierung zu HORIZONTAL und zurück triggert heißen ?
und
"Ein horizontales Layout wird mit der Konstanten BoxLayout.Y_AXIS beim Konfigurieren des Layoutmanagers erzeugt:"
-> horizontal müsste BoxLayout.X_AXIS sein, richtig ?
- Log in to post comments
BorderLayoutManager
Hallo,
Der BorderLayoutManager teilt Norden und Süden die gewünschte Breite und nicht die gewünschte Höhe zu, oder sehe ich das falsch?
Vgl. Westen / Osten.
lg
- Log in to post comments
Gute Überlegung
Schauen Sie sich mal das Bild mit den Buttons an:
- Norden und Süden sind gerade groß genug. Sie sind aber breiter als minimal notwendig.
- Osten, Westen, Mitte sind ursprünglich so breit wie sie minimal sein müssen. Zieht man das GUI in die Länge werden sie höher als notwendig.
- Log in to post comments
Rechtschreibfehler
Jede Komponente wird in ihrer Wunschgröße gargestellt???
Eigenschaften von BoxLayout
- Log in to post comments
Ereignisse und deren Behandlung
Ereignisse und deren BehandlungGUI Programme und Ereignisverarbeitung
GUI Programme laufen nicht linear ab. Bei Benutzerinteraktionen muss das Programm in der Lage sein sofort einen bestimmten Code zur Behandlung auszuführen.
Programmaktionen werden durch Benutzeraktionen getriggert. Man spricht hier von einem ereignisgesteuerten Programmablauf.
Definition: Ereignis |
---|
Ein Ereignis ist ein Vorgang in der Umwelt des Softwaresystems von vernachlässigbarer Dauer, der für das System von Bedeutung ist. |
Im Rahmen dieses Abschnitts sprechen wir von einer wichtigen Gruppe von Ereignissen den Benutzerinteraktionen:
Beispiele sind
- Mausclick
- Tasteneingabe
- Menülistenauswahl
- Zeigen auf einen Bereich des GUI
- Texteingabe oder Veränderung
Der Programmablauf wird aber auch von anderen weniger offensichtlichen Benutzerintreaktionen gesteuert
- Verdecken des Programmfensters durch ein anderes Fenster
- Fenstermodifikationen
- Vergößern, verkleinern
- Bewegen,
- Schließen eines Fenster
- Bewegen der Maus über das Programmfenster ohne Klicken (nicht auf allen Plattformen)
- Erlangen des Fokus auf einem Fenster
Ereignisklassen
Java benutzt Klassen zur Behandlung von Ereignissen (engl. Events) der Java-Benutzeroberflächen. Typische Klassen sind
Die Klassen enthalten die Beschreibung von GUI Ereignissen (z.Bsp. Maus wurde auf Position x=17, y=24 geklickt).
Sie korrelieren mit den Klassen die die grafischen Komponenten implementieren: Z.Bsp.
- Window erzeugt einen WindowEvent beim Schließen des Fensters
- JFrame einen WindowEvent beim Schließen des Fensters (JFrame ist ein Window!)
- JButton erzeugt einen ActionEvent beim Betätigen der Schaltfläche
Erzeugen von Ereignissen und deren Auswertung
Ereignisse werden automatisch von den Swingkomponenten erzeugt. Dies ist die Klasse JComponent mit ihren abgeleiteten Klassen. Sie werden zum Beispiel erzeugt, wenn ein Benutzer die Schaltfläche eines JButton betätigt. Die Aufgabe die dem Entwickler verbleibt ist die Registrierung seiner Anwendung für bestimmte GUI-Ereignisse. Die Anwendung kann nur auf Ereignisse reagieren gegen die sich sich vorher registriert hat.
Der Entwickler kann dann nach der Registrierung eines bestimmten Ereignisses ist die Auswertung des Ereignisses vornehmen und auf das Ereignis mit der gewünschten Aktion reagieren.
Java verwendet hierzu die Ereignis-Delegation um die Komponente die das Ereignis auslöst von der Ereignisbehandlung zu entkoppeln.
- Der Benutzer betätigt z.Bsp. eine Schaltfläche
- Das Laufzeitsystem erkennt das Ereignis
- Objekte die das Ereignis beobachten (engl. "Listener" in Java) werden aufgerufen und das Ereignis wird behandelt.
- Ein Listener erhält vom Laufzeitsystem ein ActionEvent-Objekt mit allen Informationen die zum Ereignis gehören.
Die Listenerobjekte müssen sich mit Hilfe einer Registrierung bei den GUI Objekten anmelden:
- Komponenten die Ereignisse erzeugen (Klasse JComponent) können, erlauben die Registrierung von "Listener" Objekten (engl. zuhören; nicht nur hören!)
- die Registrierung erfolgt mit Methoden der Syntax addXXXListener(...) der GUI Komponenten
- "Listener" Objekte implementieren das Java Interface ActionListener und damit die Methoden die beim Eintritt eines Ereignisses ausgeführt werden sollen.
Wichtig: Beziehung zwischen Listenerobjekt und GUI Objekt
Ein Listenerobjekt kann sich gegen ein oder mehrere GUI Objekte registrieren
- Registriert man ein Listenerobjekt gegen genau ein GUI Objekt (Bsp. 1 Button <-> 1 Listenerobjekt)
- muß man den Urheber des Ereignisses und den Ereignistyp nicht analysieren. Der Typ des Ereignis und das GUI Objekt sind bekannt
- Registriert man ein Listenerobjekt gegen mehrere GUI Objekte (Bsp. 3 Buttons <-> 1 Listenerobjekt)
- muß man im Listenerobjekt das übergebene Ereignisobjekt auf den Verursacher, das GUI Objekt, untersuchen
- muß man ein Listenerinterface implementieren, dass auch die Ereignisse aller Objekte verarbeiten kann.
- Beispiel: 1 Button und ein Textfeld werden von einem Listenerobjekt verwaltet. Man benötigt hier eine gemeinsame Listener-Oberklasse die beide graphische Objekte verwalten kann
Beispiel
Das folgenden Beispiel ist eine sehr einfache Implementierung eines JFrame mit einem Button und einem ActionListener:
package s2.swing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; /** * * @author s@scalingbits.com */ public class ActionListenerBeispiel implements ActionListener { @Override public void actionPerformed(ActionEvent ae) { //Ausgabe des zum ActionEvent gehörenden Kontexts System.out.println("Aktion: " + ae.getActionCommand()); } public static void main(String[] args) { JFrame myJFrame = new JFrame("Einfacher ActionListener"); myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton jb = new JButton("Hier drücken"); ActionListenerBeispiel behandeln = new ActionListenerBeispiel(); jb.addActionListener(behandeln); // Füge Listener zu Button myJFrame.add(jb); // Füge Button zu Frame myJFrame.pack(); myJFrame.setVisible(true); } // Ende main() } // Ende der Klasse
Die Klasse ActionListenerBeispiel implementiert die Methode actionPerformed() nach der Spezifikation eines ActionListener.
Das Programm startet in der main() Methode und erzeugt das folgende GUI:
- Nach klicken des Button "feuert" das Buttonobjekt jb ein Ereignis (Event)
- die Methode actionPerformed() des registrierten Listener behandeln wird mit einem Eventobjekt als Übergabeobjekt aufgerufen
- Das Eventobjekt ae wird analysiert und das
- Kommando wird als Text auf der Konsole ausgegeben:
Aktion: Hier drücken
Der Text "Hier drücken" wird ausgeben, da das Eventobjekt bei Buttons immer den Text des Buttons ausgibt.
Ereignisse (Events)
Es gibt eine reichhaltige Hierarchie von spezialisierten Event- und Listenerklassen. Hierzu sei auf die Java-Tutorials von Oracle verwiesen.
Weitere Events sind zum Beispiel:
- ItemEvent: Z. Bsp. Analysieren von JCheckBox Komponenten
- MouseEvent: Analysieren von Mausposition, Bewegung etc.
- ChangeEvent: Z. Bsp. Analysieren von Änderungen an einem JSlider
Der Swing "Event Dispatch Thread"
Damit Benutzeraktionen unabhängig vom normalen Programmablauf behandelt werden können, benutzt Swing eine eigene Ausführungseinheit, einen Thread, zum Bearbeiten der Benutzeraktionen. Dieser "Thread" ist ein Ausführungspfad der parallel zum normalen Programmablauf im main-Thread abläuft. Threads laufen parallel im gleichen Adressraum des Prozesses und haben daher Zugriff auf die gleichen Daten.
Blockieren des GUIs
Alle Aktionen der ActionListener werden vom "Swing-Event-Dispatch-Thread" ausgeführt. Diese Thread arbeitet GUI Interaktionen ab während das Javaprogramm mit anderen Threads im Hintergrund weiterlaufen kann.
Wichtig |
---|
Alle Codestrecken von zur Behandlung von Ereignissen (Methode actionPerformed()) werden in nur einem Thread aufgerufen und blockieren alle anderen Behandlungen während sie ausgeführt werden. Im Klartext: Das GUI wird während der Ausführungszeit einer Ereignisbehandlung nicht bedient und ist blockiert. Vermeiden Sie aufwändige (=langlaufende) Implementierungen in den actionPerformed() Methoden! |
Beispiel
Das folgende Programm blockiert das GUI für 2 Sekunden. Die Blockade ist nach dem Klicken an der geänderten Farbe des Buttons zu erkennen. Er bleibt gedrückt:
package s2.swing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; /** * * @author s@scalingbits.com */ public class ActionListenerBlockiert implements ActionListener { @Override public void actionPerformed(ActionEvent ae) { //Ausgabe des zum ActionEvent gehörenden Kontexts System.out.println("Aktion: " + ae.getActionCommand()); try {// Thread für 2s blockieren (schlafen) Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { JFrame myJFrame = new JFrame("Einfacher ActionListener"); myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton jb = new JButton("Hier drücken"); ActionListenerBlockiert behandeln = new ActionListenerBlockiert(); jb.addActionListener(behandeln); // Füge Listener zu Button myJFrame.add(jb); // Füge Button zu Frame myJFrame.pack(); // Berechne Layout myJFrame.setVisible(true); } }
Synchronisation mit Swing GUIs
|
- 7691 views
Erzeugen von Ereignissen und deren Auswertung
Sollte der zweite Absatz unter der Überschrift eigentlich so formuliert sein?
"Der Entwickler kann dann nach der Registrierung eines bestimmten Ereignisses die Auswertung des Ereignisses vornehmen und auf das Ereignis mit der gewünschten Aktion reagieren."
Und beim ersten Beispiel steht: "Nach klicken des Button "feuert" ..."
Dort ist der Button "Hier klicken" gemeint, oder?
- Log in to post comments
ActionListenerBeispiel
In dem Beispiel:
ActionListenerBeispiel behandeln = new ActionListenerBeispiel();
--> jb.addActionListener(behandeln); // Füge Listener zu Button
myJFrame.add(jb); // Füge Button zu Frame
myJFrame.setVisible(true);
myJFrame.pack();
müsste der Listener der auf jb registriert wird, "ActionListenerBeispiel" heißen oder?
- Log in to post comments
Antwort
Ich bin mir nicht ganz sicher, dass wir über das gleiche sprechen.
Kommunikation über diese Kommentare haben ihre Grenzen.
behandeln ist ein Zeiger auf ein Objekt ActionListenerBeispiel.
Dieses Objekt wird beim dem Objekt jb mit addActionListener registriert.
Das Programm übersetzt und funktioniert auch.
- Log in to post comments
Event-Interface und Event-Adapter
Event-Interface und Event-AdapterDie Implementierung eines einfachen ActionListener-Schnittstelle ist recht einfach, da nur eine Methode implementiert werden muss.
Viele nicht triviale ActionListener erfordern jedoch die Implementierung von mehreren Methoden aufgrund der Komplexität der entsprechenden Komponente. Ein Beispiel hierfür ist die Schnittstelle MouseListener. Sie erfordert die Implementierung der folgenden Methoden:
- mouseClicked(MouseEvent e)
- mouseEntered()
- mouseExited()
- mousePressed()
- mouseReleased()
Dies ist aufwändig wenn man sich nur für ein bestimmtes Ereignis wie z. Bsp. mouseReleased() interessiert. Man muss alle Interfacemethoden implementieren. Vier der Methoden bleiben leer und sind überflüssig.
Listener-Adapter Klassen
Um diese unnötige Schreibarbeit zu vermeiden, stellt Swing nach dem Entwurfsmuster Adapter Klassen als abstrakte Klassen mit leeren, aber schon implementierten Methoden zur Verfügung.
Vorteil: Der Entwickler kann seine Klasse aus der abstrakten Klasse ableiten und muss nur die Methoden für die Ereignisse implementieren die ihn interessieren.
Für die Implementierung von Maus-Events steht zum Beispiel die Klasse MouseAdapter zur Verfügung, die die entsprechenden Methoden implementiert.
Einige der Adapterklassen die Swing zur vereinfachten Implementierung von Ereignisschnittstellen (Event Interface) sind:
Spezialisierungen der Schnittsteller EventListener | Adapterklasse |
---|---|
ComponentListener | ComponentAdapter |
ContainerListener | ContainerAdapter |
FocusListener | FocusAdapter |
KeyListener | KeyAdapter |
MouseListener | MouseAdapter |
MouseMotionListener | MouseMotionAdapter |
WindowListener | WindowAdapter |
Im folgenden Beispiel wird die Klasse MouseAdapterTest aus der abstrakten Klasse MouseAdapter abgeleitet um nur die Methode mouseClicked() implementieren zu müssen:
package s2.swing; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JFrame; public class MouseAdapterTest extends MouseAdapter { public MouseAdapterTest() { erzeugeGUI(); } public static void main(String[] args) { MouseAdapterTest mat = new MouseAdapterTest(); } private void erzeugeGUI() { JFrame myJFrame = new JFrame("Mouse Click Adapter Test"); myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton jb = new JButton("Hier drücken"); jb.addMouseListener(this); myJFrame.getContentPane().add(jb); myJFrame.pack(); myJFrame.setVisible(true); } @Override public void mouseClicked(MouseEvent mEvent) { System.out.println("MouseClick wurde auf Position [" + mEvent.getX() + "," + mEvent.getY() + "] " + mEvent.getClickCount() + " mal geklickt"); } } // Ende der Klasse
Das Programm registriert sich selbst gegen den Button und ist jetzt in der Lage, die Information des dEventobjekts mEvent auszulesen (x,y Position, Anzahl der Mehrfachclicks).
Beispiel
Im Diagramm (unten) sind die beiden Möglichkeiten aufgeführt die ein Entwickler zum Auslesen eines Mauscklicks benutzen kann. Die von Java zur Verfügung gestellten Infrastruktur besteht aus dem zu implementierenden Interface MouseListener und einer abstrakten Klasse Mouseadapter:
Ein Entwickler der sich nur gegen das MouseClick Ereignis registrieren möchte, kann wie im Diagramm oben:
- das Interface MouseListener in z.Bsp. der Klasse ListenerAufwaendig implementieren. Hier müssen alle 5 Methoden des Interface implementiert werden. Die vier nicht benötigten Methoden können als leere Methoden implementiert werden.
- aus der abstrakten Klasse MouseAdapter eine Klasse wie z.Bsp. ListenerEinfach ableiten. In ihr muss man nur eine einzige Methode mouseClicked() durch Überschreiben implementieren. Die anderen vier Methoden sind schon in der Klasse MouseAdapter als leere Proformamethoden implementiert. Beim Ableiten aus der abstrakten Klasse MouseAdapter müssen nur die gewünschten Methoden überschrieben werden. Ein Konstruktor ist nicht nötig, da die Klasse MouseAdapter einen Default-Konstruktor besitzt.
Anbei die vollständige Implementierung der semantisch gleichwertigen Methoden:
Klasse ListenerAufwaendig | Klasse ListenerEinfach |
---|---|
package s2.swing; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class ListenerAufwaendig implements MouseListener{
@Override public void mouseClicked(MouseEvent mEvent) {
System.out.println("MouseClick wurde auf Position ["
+ mEvent.getX() + ","
+ mEvent.getY() + "] "
+ mEvent.getClickCount() + " mal geklickt");
}
@Override public void mouseEntered(MouseEvent mEvent)
{ /* leere Implementierung, erzwungen */ }
@Override public void mouseExited(MouseEvent mEvent)
{ /* leere Implementierung, erzwungen */ }
@Override public void mousePressed(MouseEvent mEvent)
{ /* leere Implementierung, erzwungen */ }
@Override public void mouseReleased(MouseEvent mEvent)
{ /* leere Implementierung, erzwungen */ }
}
|
package s2.swing; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class ListenerEinfach extends MouseAdapter{ @Override public void mouseClicked(MouseEvent mEvent) { System.out.println("MouseClick wurde auf Position [" + mEvent.getX() + "," + mEvent.getY() + "] " + mEvent.getClickCount() + " mal geklickt"); } } |
- 6303 views
Anonyme und innere Klassen
Anonyme und innere KlassenNach den bisher vorgestellten Prinzipien erfordert die Implementierung eines GUI die Implementierung von vielen Listenern und führt zur Erzeugung sehr vieler Klassen. Java erlaubt hier die Implementierung von anoymen, inneren Klassen die nur im Kontext einer bestimmten Klasse existieren und den Namensraum der Klassen nicht unnötig belasten.
Innere Klassen
Innere Klassen helfen es zu vermeiden, dass man Klassen veröffentlicht die nur von genau einer anderen Klasse benutzt werden. Innere Klassen werden syntaktisch wie normale Klassen implementiert. Der einzige Unterschied ist, dass sie im Block einer äusseren Klasse implementiert werden. Sie werden in der äusseren Klasse mit dem gleichen Block der äusseren Klasse wie die Klassenvariablen und Methoden der äusseren Klasse implementiert.
Die in der Vorlesung vorgestellten inneren Klassen sind Elementklassen.
Definition Elementklasse |
---|
Elementklassen sind wie Instanzmethoden und Instanzvariablen Elemente einer (anderen) Klasse. Sie werden auf der gleichen Blockebene wie Instanzmethoden und Instanzvariablen implementiert. Sie haben einen Zugriffschutz wie Instanzmethoden und Instanzvariablen. |
Innere Klassen können auch als lokale Klasse innerhalb eines beliebigen Blocks implementiert werden. Diese Variante ist nicht Gegenstand der Vorlesung.
Die inneren Klassen gehören zum Paket der äusseren Klasse. Importkommandos müssen in der äusseren Klasse implementiert werden.
Besondere Eigenschaften von Elementklassen |
---|
Instanzen von Elementklassen sind Komponenten des umgebenden Objekts! |
Das vorhergehende Beispiel kann jetzt wie folgt implementiert werden:
package s2.swing; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JFrame; /** * * @author s@scalingbits.com */ public class MouseAdapterInnereKlasseTest { /** * Die innere Klasses MyMouseListener */ class MyMouseListener extends MouseAdapter { @Override public void mouseClicked(MouseEvent mEvent) { System.out.println("MouseClick wurde auf Position [" + mEvent.getX() + "," + mEvent.getY() + "] " + mEvent.getClickCount() + " mal geklickt"); } } /** * Erzeuge GUI im Konstruktor */ public MouseAdapterInnereKlasseTest() { JFrame myJFrame = new JFrame("Mouse Click Innere Klasse Test"); myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton jb = new JButton("Hier drücken"); jb.addMouseListener(new MyMouseListener()); myJFrame.getContentPane().add(jb); myJFrame.pack(); myJFrame.setVisible(true); } public static void main(String[] args) { MouseAdapterInnereKlasseTest mat = new MouseAdapterInnereKlasseTest(); } }
Die Unterschiede sind die Folgenden:
- Die Klasse MouseAdapterInnereKlasseTest muss nicht mehr von der Klasse MouseAdapter abgeleitet werden oder eine Schnitstelle MouseEvent implementieren
- Es wird eine eigene innere Klasse MyMouseListener implementiert die nicht ausserhalb der umgebenden Klasse bekannt ist.
- Die Klasse MyMouseListener erbt (extends Schlüsselwort) von der Klasse MouseAdapter.
- Beim Hinzufügen eines Listeners zum Button wird eine Instanz der inneren Klasse erzeugt.
Diese innere Klasse hat für den Entwickler den Vorteil, dass er keine neuen Klassen nach aussen hin bekanntmachen muss. Die Implementierung des Listeners erfolgt in der gleichen Datei. Die Implementierung des Listener ist also visuell näher als wenn sie in einer eigenen Klasse und einer eigenen Datei geschehen würde.
Objektabhängigkeit von Instanzen innerer Klassen
Im obigen Beispiel wird eine Instanz der Klasse MyMouseListener erzeugt. Dies ist nur erlaubt wenn das Objekt aus dem Kontext (Methode) eines Objekts der Klasse MouseAdapterInnereKlasseTest erzeugt wird. Dieses äussere Objekt existiert, da die innere Klasse im Konstruktor von MouseAdapterInnereKlasseTest erzeugt wird.
Der Code zum Erzeugen des GUI im Konstruktor kann nicht einfach in die statische main() Methode kopiert werden. Hier gibt es noch keinen Kontext zu einem Objekt der Klasse MouseAdapterInnereKlasseTest. Der javac Übersetzer wird einen Fehler melden.
Anonyme, innere Klasse
Für Swing wurde das Konzept der anonymen, inneren Klasse entwickelt.
Definition anonyme, innere Klasse |
---|
Eine anonyme, innere Klasse ist eine lokale Klasse ohne Namen die innerhalb eines Ausdrucks (Block) definiert und instanziiert wird. |
Anonyme, innere Klassen haben keinen Namen und daher auch keine Konstruktoren. Sie werden typischerweise als Implementierungen für Adapterklassen oder Schnittstellen verwendet.
Beispiel
Anonyme, innere Klassen erlauben die benötigte Listenerimplementierung noch eleganter durchzuführen:
An der Stelle an der eine Instanz eines Listeners benötigt wird kann man auch direkt eine vollständige Klasse implementieren und instanziieren.
Das folgende Beispiel hat die gleiche Funktion wie das vorgehende Beispiel mit der Implementierung einer inneren Klasse. Es kommt aber ohne einen eigenen Klassennamen aus:
package s2.swing; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JFrame; public class MouseAdapterAnonymeInnereKlasseTest { /** * Erzeuge GUI im Konstruktor */ public MouseAdapterAnonymeInnereKlasseTest() { JFrame myJFrame = new JFrame("Mouse Click Adapter Test"); myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton jb = new JButton("Hier drücken"); jb.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent mEvent) { System.out.println("MouseClick wurde auf Position [" + mEvent.getX() + "," + mEvent.getY() + "] " + mEvent.getClickCount() + " mal geklickt"); } }); myJFrame.getContentPane().add(jb); myJFrame.pack(); myJFrame.setVisible(true); } public static void main(String[] args) { MouseAdapterAnonymeInnereKlasseTest mat = new MouseAdapterAnonymeInnereKlasseTest(); } }
InteressantEine anonyme, innere Klasse kann...
Wichtig: Es müssen alle Methoden implementiert werden, die notwendig sind um die Klasse zu instanzieren |
Die Unterschiede sind die Folgenden:
- Die Klasse MouseAdapterInnereAnonymeKlasseTest muss nicht mehr von MouseAdapter abgeleitet werden oder einen MouseEvent implementieren
- Beim Hinzufügen eines Listeners zum Button wird
- mit dem new Operator eine Instanz einer anonymen Klasse angelegt, die die abstrakte Klasse MouseAdapter implementiert. Sie ist anonym da sie selbst keinen Namen besitzt.
- die anonyme Klasse wird innerhalb der Klasse MouseAdapterInnereAnonymKlasseTest soweit wie nötig implementiert um aus der abstrakten Oberklasse eine normale Klasse zu erzeugen
Diese "Hilfskonstruktion" hat für den Entwickler eine Reihe von Vorteilen:
- Das Ereignis kann textuell sehr nahe an der Erzeugung der Komponente implementiert werden. Der Code wird übersichtlicher
- Es müssen keine neuen Klassen mit eigenen Namen erzeugt werden. Hierdurch wird die gesamte Klassenhierarchie übersichtlicher und deutlich kleiner.
Statische innere Klassen, nicht anonyme lokale Klassen
... sind nicht Gegenstand dieser Vorlesung.
- 15871 views
1. MouseAdapterInnereKlasseTest
Für das 1. Code Beispiel "MouseAdapterInnereKlasseTest", heißt die Innere Klasse nicht "MyMouseListener" anstatt wie in der Erklärung darunter "MyMouseClicked" beschrieben?
Entschuldigen Sie falls der Fehler schon in der Vorlesung gefunden wurde, ich war heute krank.
MfG
- Log in to post comments
Korrekte Beobachtung
Danke für den Hinweis. Der Text wurde korrigiert. Die beiden Programmierbeispiele wurden um eine Methode entschlackt und sind jetzt kürzer und hoffentlich besser lesbar.
- Log in to post comments
Müsste es dann in der
Müsste es dann in der Erklärung nicht statt:
"Die Klasse MyMouseClicked implementiert das MouseAdapter"
...
"Die Klasse MyMouseListener implementiert das MouseAdapter"
... heißen ?
- Log in to post comments
kleiner Rechtschreibefehler
Hallo Herr Schneider,
mir ist ein kleiner Rechtschreibefehler aufgefallen. Bei den besonderen Eigenschaften von Elementklassen haben sie beim ersten Punkt umschliesen anstatt umschließen geschrieben.
freundliche Grüße
- Log in to post comments
Danke, wurde verbessert.
Danke für die Wertschätzung der deutschen Sprache.
Fehler wird verbessert.
- Log in to post comments
Übungen (Swing)
Übungen (Swing)Ausnahmefenster
Implementieren Sie ein Fenster mit Hilfe der Klasse JFrame zur Behandlung von Ausnahmen.
- Das JFrame soll beim Auftreten einer Ausnahmen aufgerufen werden und den Namen der Ausnahme zeigen.
- Das Programm soll dann auf Wunsch beendet werden oder es soll ein Stacktrace auf der Konsole angezeigt werden
- Das Programm soll ein Bild aus dem Internet als Label verwenden
Das Fenster soll in etwa wie das folgende GUI aussehen:
Verwenden Sie das Rahmenprogramm AusnahmeFenster.java welches eine Infrastruktur zum Testen zur Verfügung stellt:
package s2.swing;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class AusnahmeFenster {
final private JFrame hf;
final private JButton okButton;
final private JButton exitButton;
final private Exception myException;
/**
* Aufbau des Fensters zur Ausnahmebehandlung
*
* @param fehlermeldung ein beliebiger Fehlertext der angezeigt wird
* @param e Die Ausnahme die angezeigt werden soll
*/
public AusnahmeFenster(String fehlermeldung, Exception e) {
JLabel logo;
JPanel buttonPanel;
myException = e;
// 1. Erzeugen einer neuen Instanz eines Swingfensters
System.out.println("Hier beginnt die Arbeit: Löschen Sie dieses Kommando");
// ...
hf = null;
// 3. Gewünschte Größe setzen
// 1. Parameter: horizontale Größe in Pixel: 220
// 2. Parameter: vertikale Größe: 230
// ...
// 8. Labelerzeugung
logo = meinLogo();
// 4. Nicht Beenden bei Schliessen des Fenster
// 5. Anlegen der Buttons
okButton = null;
exitButton= null;
// 10. Hinzügen der Eventbehandlung
// Tipp: Die Klasse muss noch das Interface ActionListener implementieren!
// ...
// 6. Aufbau des Panels
// ...
// 7. Aubau des ContentPanes
// ...
// 2.1 Das Layout des JFrame berechnen.
// ...
// 3. Gewünschte Größe setzen
// 1. Parameter: horizontale Größe in Pixel
// 2. Parameter: vertikale Größe
// ...
// 2.2 Sichtbar machen des JFrames. Immer im Vordergrund
// ...
// ...
}
/**
* Implementieren des Logos
* 9.ter Schritt
* @return Zeiger auf das Logoobjekt
*/
private JLabel meinLogo() {
URL logoURL;
JLabel logoLabel;
String myURL = "https://upload.wikimedia.org/wikipedia/commons/0/01/DHBW_MA_Logo.jpg";
try {
logoURL = new URL(myURL);
ImageIcon myImage = new ImageIcon(logoURL);
logoLabel = new JLabel(myImage);
} catch (java.net.MalformedURLException e) {
System.out.println(e);
System.out.println("Logo URL kann nicht aufgelöst werden");
logoLabel = new JLabel("Logo fehlt");
}
return logoLabel;
}
/**
* Behandlung der JButton-Ereignisse
* 11. ter Schritt
* @param e
*/
public void actionPerformed(ActionEvent e) {
//System.exit(0);
//System.out.println("OK Button clicked");
//myException.printStackTrace();
}
/**
* Hauptprogramm zum Testen des Ausnahmefensters
* @throws Exception
*/
public static void main(String[] args) {
AusnahmeFenster dasFenster;
try {
myTestMethod();
} catch (Exception e) {
dasFenster = new AusnahmeFenster("Hier läuft etwas schief", e);
}
}
/**
* Eine Testmethode die mit einer Division durch Null eine
* Ausnahme provoziert
* @throws Exception
*/
public static void myTestMethod() throws Exception {
int a = 5;
int b = 5;
int c = 10;
c = c / (a - b);
System.out.println("Programm regulär beendet");
}
}
Empfehlung: Bauen Sie das GUI schrittweise auf und testen Sie es Schritt für Schritt
- Erzeugen eines einfachen JFrame
- Sichtbarmachen des JFrame
- Größe des JFrames setzen
- Programm nach Schließen des JFrames weiterlaufen lassen
- Anlegen der Buttons
- Aufbau des Panels
- Verbinden von Buttons, Panel und JFrame
- Erzeugen des Labels mit dem GIF und Hinzufügen zum Pane
- Implementieren des Labels mit Logo
- Hinzufügen der ActionListener zu den Buttons
- Implementieren der Aktionen
Taschenrechner
Implementieren Sie einen Taschenrechner mit den vier Grundrechenarten.
Benutzen Sie hierfür die Aufgabenstellung der Universität Bielefeld von Herrn Jan Krüger:
- Aufgabenstellung
- Quellen und Rahmenprogramm: Calculator.tar.gz
Innere Klasse und anonyme Klasse
Das Programm der vorhergehenden Übung (Ausnahmefenster) benutzt in der Musterlösung eine einzige Methode actionPerformed() in der Klasse AusnahmeFenster um die Aktionen der beiden Buttons auszuführen.
public class AusnahmeFensterFertig implements ActionListener {
...
public AusnahmeFenster(String fehlermeldung, Exception e) {
...
okButton = new JButton();
exitButton = new JButton();
// 10. Hinzügen der Eventbehandlung
okButton.addActionListener(this);
exitButton.addActionListener(this);
...
}
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) (e.getSource());
if (source == exitButton) {
System.exit(0);
}
if (source == okButton) {
System.out.println("OK Button clicked");
myException.printStackTrace();
}
}
}
Aufgabe 1:
- Implementieren Sie eine externe Klasse SystemExitListener die als Listener für den "Beenden" Button genutzt werden kann.
- Ändern Sie die Klasse AusnahmeFenster derart,dass Sie für den "Beenden" Button nicht mehr das Ausnahmefenster als Objekt registrieren (this). Erzeugen Sie als registrierten Listener eine Instanz der Klasse SystemExitListener.
Sie haben nun eine eigene Klasse mit einem eigenen Objekt zur Behandlung des "Beenden" Ereignisses
Weiterführend (optional)
Implementieren Sie einen Menüeintrag "Beenden" in einer Menüleiste mit dem EIntrag "Ablage".
Herangehen:
|
Aufgabe 2:
- Die Klasse AusnahmeFenster soll NICHT mehr die Schnittstelle ActionListener implementieren.
- Implementieren Sie eine innere Klasse SystemExitAction. Sie soll einen ActionListener implementieren, der das Programm beendet.
- Ändern sie den Aufruf addActionListener() des exitButton so, dass er die Klasse SystemExitAction benutzt.
- Ändern Sie den Aufruf addActionListener() des okButton so, dass eine anonyme innere Klasse aufgerufen wird die einen Stacktrace ausdruckt
Hierdurch entfällt die Analyse der auslösenden Aktion in der ursprünglichen Implementierung. Für jede Aktion wurde jetzt eine eigene Methode implementiert
- 8379 views
Lösungen (Swing)
Lösungen (Swing)Ausnahmefenster
package s2.swing;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class AusnahmeFensterLoesung implements ActionListener {
final private JFrame hf;
final private JButton okButton;
final private JButton exitButton;
final private Exception myException;
/**
* Aufbau des Fensters zur Ausnahmebehandlung
*
* @param fehlermeldung ein beliebiger Fehlertext der angezeigt wird
* @param e Die Ausnahme die angezeigt werden soll
*/
public AusnahmeFensterLoesung(String fehlermeldung, Exception e) {
JLabel logo;
JPanel buttonPanel;
myException = e;
hf=null;
okButton=null;
exitButton=null;
// 1. Erzeugen einer neuen Instanz eines Swingfensters
hf = new JFrame("Anwendungsfehler");
// 8. Labelerzeugung
logo = meinLogo();
// 4. Beenden bei Schliesen des Fenster
hf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 5. Anlegen der Buttons
okButton = new JButton();
okButton.setText("Stack Trace");
exitButton = new JButton();
exitButton.setText("Beenden");
// 10. Hinzügen der Eventbehandlung
okButton.addActionListener(this);
exitButton.addActionListener(this);
// 6. Aufbau des Panels
buttonPanel = new JPanel(new GridLayout(1, 0));
buttonPanel.add(exitButton);
buttonPanel.add(okButton);
JTextArea fehlertextArea = new JTextArea(2, 20);
fehlertextArea.append(fehlermeldung + "\n");
fehlertextArea.append("Exception: "+ myException);
// 7. Aubau des ContentPanes
Container myPane = hf.getContentPane();
myPane.setLayout(new BorderLayout());
myPane.add(logo, BorderLayout.NORTH);
myPane.add(fehlertextArea, BorderLayout.CENTER);
myPane.add(buttonPanel, BorderLayout.SOUTH);
// 2.1 Das Layout des JFrame berechnen.
hf.pack();
// 3. Gewünschte Größe setzen
// 1. Parameter: horizontale Größe in Pixel
// 2. Parameter: vertikale Größe
hf.setSize(350, 300);
// 2.2 Sichtbar machen des JFrames. Immer im Vordergrund
hf.setVisible(true);
hf.setAlwaysOnTop(true);
}
/**
* Implementieren des Logos
* 9.ter Schritt
* @return Zeiger auf das Logoobjekt
*/
private JLabel meinLogo() {
URL logoURL;
JLabel logoLabel;
String myURL = "https://upload.wikimedia.org/wikipedia/commons/0/01/DHBW_MA_Logo.jpg;
try {
logoURL = new URL(myURL);
ImageIcon myImage = new ImageIcon(logoURL);
logoLabel = new JLabel(myImage);
} catch (java.net.MalformedURLException e) {
System.out.println(e);
System.out.println("Logo URL kann nicht aufgelöst werden");
logoLabel = new JLabel("Logo fehlt");
}
return logoLabel;
}
/**
* Behandlung der JButton Ereignisse
* 11. ter Schritt
* @param e
*/
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) (e.getSource());
if (source == exitButton) {
System.exit(0);
}
if (source == okButton) {
System.out.println("OK Button clicked");
myException.printStackTrace();
}
}
/**
* Hauptprogramm zum Testen des Ausnahmefensters
* @throws Exception
*/
public static void main(String[] args) {
AusnahmeFensterLoesung dasFenster;
try {myTestMethod();}
catch (Exception e) {
dasFenster = new AusnahmeFensterLoesung("Hier läuft etwas schief",e);
}
}
/**
* Eine Testmethode die eine durch eine Division durch Null eine
* Ausnahme provoziert
* @throws Exception
*/
public static void myTestMethod() throws Exception {
int a = 5;
int b = 5;
int c = 10;
c = c / (a-b);
System.out.println("Programm regulär beendet");
}
}
Taschenrechner
Die Universität Bielefeld (Herr Jan Krüger) bieten die Lösung der Programmieraufgabe an unter:
Innere und anonyme Klasse
Aufgabe 1
Klasse SystemExitListener
package s2.swing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * * @author s@scalingbits.com * Implementierung eines ActionListener der als Aktion die Anwendung * beendet */ public class SystemExitListener implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }
Einfügen eines Menüs (Optional)
import javax.swing.*; ... JMenuItem jmi = new JMenuItem("Beenden"); jmi.addActionListener(new SystemExitListener()); JMenu jm = new JMenu("Ablage"); jm.add(jmi); JMenuBar jmb = new JMenuBar(); jmb.add(jm); hf.setJMenuBar(jmb);
Aufgabe 2
Hinweis: Die Klasse wurde in AusnahmeFensterInnerer umbenannt
}
hf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- 5399 views
Zu Übung 1 (Swing)
Wie in der Veranstaltung: hf.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); sollte sein hf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); damit das Programm beim Schließen des Fensters beendet wird. Viele Grüße
- Log in to post comments
Danke für die Erinnerung.
habe den Code verbessert.
Kommentar für die nicht Eingeweihten:
Mit diesen beiden Optionen kann man steuern ob die gesamte Anwendung bei schliesen des Fensters beendet wird. In der Übung macht das Beenden der Anwendung Sinn, da man sonst nichts mehr machen kann. Bei realen Anwendungen ist es oft besser wenn man die Anwendung nicht beendet weil es oft Ikonen oder Menüleisten gibt, die es erlauben neue Fenster zu öffnen.
- Log in to post comments
Lernziele (Swing, innere und anonyme Klassen)
Lernziele (Swing, innere und anonyme Klassen)
Am Ende dieses Blocks können Sie:
|
Lernzielkontrolle
Sie sind in der Lage die folgenden Fragen zu beantworten:Fragen zur graphischen Programmierung (Swing)
- 3547 views