GUI 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 Benutzerintreaktionenr gesteuert
- Verdecken des Programmfensters durch ein anderes
- Vergrößern des Fensters
- 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 Javabenutzeroberflächen. Typische Klassen sind
- ActionEvent
- WindowsEvent
- KeyEvent etc.

Sie korrelieren mit den Klassen die die grafischen Komponenten implementieren: Z.Bsp.
- Window erzeugt WindowEvent beim Schließen des Fensters
- JFrame erzeugt WindowEvent beim Schließen des Fensters
- JButton erzeugt ActionEvent beim Betätigen der Schaltfläche
Erzeugen von Ereignissen und deren Auswertung
Ereignisse werden automatisch von den Swingkomponenten erzeugt. 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 registrieren.

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 Kurs2.Swing;import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;public class ActionListenerBeispiel implements ActionListener {
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.setVisible(true);
myJFrame.pack();
}
}
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 Events (Methode actionPerformed()) werden in nur einem Thread aufgerufen und blockieren alle anderen Events während sie ausgeführt werden. Das GUI wird während der Ausführungszeit nicht bedient und ist blockiert. Vermeiden Sie aufwändige 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 Kurs2.Swing;import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;public class ActionListenerBlockiert implements ActionListener {
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.setVisible(true);
myJFrame.pack();
}
}
Synchronisation mit Swing GUIs
| Wichtig |
|---|
| Die meisten Swing Komponenten sind nicht synchronisiert. Veränderungen an den Datenstrukturen durch nicht synchronisertern Zugriff von anderen Threads können zu Inkonsistenzen führen. |
