Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.
 
Inhaltsverzeichnis
Vorwort
1 Neues in Java 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 10 Grafische Oberflächen mit Swing
Pfeil 10.1 AWT, JavaFoundation Classes und Swing
Pfeil 10.1.1 Das Abstract Window Toolkit (AWT)
Pfeil 10.1.2 Java Foundation Classes (JFC)
Pfeil 10.1.3 Was Swing von AWT-Komponenten unterscheidet
Pfeil 10.2 Mit NetBeans zur ersten Swing-Oberfläche
Pfeil 10.2.1 Projekt anlegen
Pfeil 10.2.2 Eine GUI-Klasse hinzufügen
Pfeil 10.2.3 Programm starten
Pfeil 10.2.4 Grafische Oberfläche aufbauen
Pfeil 10.2.5 Swing-Komponenten-Klassen
Pfeil 10.2.6 Funktionalität geben
Pfeil 10.3 Aller Swing-Anfang – Fenster zur Welt
Pfeil 10.3.1 Eine Uhr, bei der die Zeit nie vergeht
Pfeil 10.3.2 Swing-Fenster mit javax.swing.JFrame darstellen
Pfeil 10.3.3 Mit add(…) auf den Container
Pfeil 10.3.4 Fenster schließbar machen – setDefaultCloseOperation(int)
Pfeil 10.3.5 Sichtbarkeit des Fensters
Pfeil 10.3.6 Größe und Position des Fensters verändern
Pfeil 10.3.7 Fenster- und Dialogdekoration, Transparenz *
Pfeil 10.3.8 Die Klasse Toolkit *
Pfeil 10.3.9 Zum Vergleich: AWT-Fenster darstellen *
Pfeil 10.4 Beschriftungen (JLabel)
Pfeil 10.4.1 Mehrzeiliger Text, HTML in der Darstellung
Pfeil 10.5 Icon und ImageIcon für Bilder auf Swing-Komponenten
Pfeil 10.5.1 Die Klasse ImageIcon
Pfeil 10.6 Es tut sich was – Ereignisse beim AWT
Pfeil 10.6.1 Die Ereignisquellen und Horcher (Listener) von Swing
Pfeil 10.6.2 Listener implementieren
Pfeil 10.6.3 Listener bei dem Ereignisauslöser anmelden/abmelden
Pfeil 10.6.4 Adapterklassen nutzen
Pfeil 10.6.5 Innere Mitgliedsklassen und innere anonyme Klassen
Pfeil 10.6.6 Aufrufen der Listener im AWT-Event-Thread
Pfeil 10.6.7 Ereignisse, etwas genauer betrachtet *
Pfeil 10.7 Schaltflächen
Pfeil 10.7.1 Normale Schaltflächen (JButton)
Pfeil 10.7.2 Der aufmerksame ActionListener
Pfeil 10.7.3 Schaltflächen-Ereignisse vom Typ ActionEvent
Pfeil 10.7.4 Basisklasse AbstractButton
Pfeil 10.7.5 Wechselknopf (JToggleButton)
Pfeil 10.8 Textkomponenten
Pfeil 10.8.1 Text in einer Eingabezeile
Pfeil 10.8.2 Die Oberklasse der Textkomponenten (JTextComponent)
Pfeil 10.8.3 Geschützte Eingaben (JPasswordField)
Pfeil 10.8.4 Validierende Eingabefelder (JFormattedTextField)
Pfeil 10.8.5 Einfache mehrzeilige Textfelder (JTextArea)
Pfeil 10.8.6 Editor-Klasse (JEditorPane) *
Pfeil 10.9 Swing Action *
Pfeil 10.10 JComponent und Component als Basis aller Komponenten
Pfeil 10.10.1 Hinzufügen von Komponenten
Pfeil 10.10.2 Tooltips (Kurzhinweise)
Pfeil 10.10.3 Rahmen (Border) *
Pfeil 10.10.4 Fokus und Navigation *
Pfeil 10.10.5 Ereignisse jeder Komponente *
Pfeil 10.10.6 Die Größe und Position einer Komponente *
Pfeil 10.10.7 Komponenten-Ereignisse *
Pfeil 10.10.8 UI-Delegate – der wahre Zeichner *
Pfeil 10.10.9 Undurchsichtige (opake) Komponente *
Pfeil 10.10.10 Properties und Listener für Änderungen *
Pfeil 10.11 Container
Pfeil 10.11.1 Standardcontainer (JPanel)
Pfeil 10.11.2 Bereich mit automatischen Rollbalken (JScrollPane)
Pfeil 10.11.3 Reiter (JTabbedPane)
Pfeil 10.11.4 Teilungskomponente (JSplitPane)
Pfeil 10.12 Alles Auslegungssache – die Layoutmanager
Pfeil 10.12.1 Übersicht über Layoutmanager
Pfeil 10.12.2 Zuweisen eines Layoutmanagers
Pfeil 10.12.3 Im Fluss mit FlowLayout
Pfeil 10.12.4 BoxLayout
Pfeil 10.12.5 Mit BorderLayout in alle Himmelsrichtungen
Pfeil 10.12.6 Rasteranordnung mit GridLayout
Pfeil 10.12.7 Der GridBagLayoutmanager *
Pfeil 10.12.8 Null-Layout *
Pfeil 10.12.9 Weitere Layoutmanager
Pfeil 10.13 Rollbalken und Schieberegler
Pfeil 10.13.1 Schieberegler (JSlider)
Pfeil 10.13.2 Rollbalken (JScrollBar) *
Pfeil 10.14 Kontrollfelder, Optionsfelder, Kontrollfeldgruppen
Pfeil 10.14.1 Kontrollfelder (JCheckBox)
Pfeil 10.14.2 ItemSelectable, ItemListener und das ItemEvent
Pfeil 10.14.3 Sich gegenseitig ausschließende Optionen (JRadioButton)
Pfeil 10.15 Fortschritte bei Operationen überwachen *
Pfeil 10.15.1 Fortschrittsbalken (JProgressBar)
Pfeil 10.15.2 Dialog mit Fortschrittsanzeige (ProgressMonitor)
Pfeil 10.16 Menüs und Symbolleisten
Pfeil 10.16.1 Die Menüleisten und die Einträge
Pfeil 10.16.2 Menüeinträge definieren
Pfeil 10.16.3 Einträge durch Action-Objekte beschreiben
Pfeil 10.16.4 Mit der Tastatur – Mnemonics und Shortcut
Pfeil 10.16.5 Der Tastatur-Shortcut (Accelerator)
Pfeil 10.16.6 Tastenkürzel (Mnemonics)
Pfeil 10.16.7 Symbolleisten alias Toolbars
Pfeil 10.16.8 Popup-Menüs
Pfeil 10.16.9 System-Tray nutzen *
Pfeil 10.17 Das Model-View-Controller-Konzept
Pfeil 10.18 Auswahlmenüs, Listen und Spinner
Pfeil 10.18.1 Listen (JList)
Pfeil 10.18.2 Auswahlmenü (JComboBox)
Pfeil 10.18.3 Drehfeld (JSpinner) *
Pfeil 10.18.4 Datumsauswahl
Pfeil 10.19 Tabellen (JTable)
Pfeil 10.19.1 Ein eigenes Tabellen-Model
Pfeil 10.19.2 Basisklasse für eigene Modelle (AbstractTableModel)
Pfeil 10.19.3 Ein vorgefertigtes Standardmodell (DefaultTableModel)
Pfeil 10.19.4 Ein eigener Renderer für Tabellen
Pfeil 10.19.5 Zell-Editoren
Pfeil 10.19.6 Automatisches Sortieren und Filtern mit RowSorter *
Pfeil 10.20 Bäume (JTree)
Pfeil 10.20.1 JTree und sein TreeModel und TreeNode
Pfeil 10.20.2 Selektionen bemerken
Pfeil 10.20.3 Das TreeModel von JTree *
Pfeil 10.21 JRootPane und JDesktopPane *
Pfeil 10.21.1 Wurzelkomponente der Top-Level-Komponenten (JRootPane)
Pfeil 10.21.2 JDesktopPane und die Kinder von JInternalFrame
Pfeil 10.21.3 JLayeredPane
Pfeil 10.22 Dialoge und Window-Objekte
Pfeil 10.22.1 JWindow und JDialog
Pfeil 10.22.2 Modal oder nichtmodal?
Pfeil 10.22.3 Standarddialoge mit JOptionPane
Pfeil 10.22.4 Der Dateiauswahldialog
Pfeil 10.22.5 Der Farbauswahldialog JColorChooser *
Pfeil 10.23 Flexibles Java-Look-and-Feel
Pfeil 10.23.1 Look-and-Feel global setzen
Pfeil 10.23.2 UIManager
Pfeil 10.23.3 Die Windows-Optik mit JGoodies Looks verbessern *
Pfeil 10.24 Swing-Komponenten neu erstellen oder verändern *
Pfeil 10.24.1 Überlagerungen mit dem Swing-Komponenten-Dekorator JLayer
Pfeil 10.25 Die Zwischenablage (Clipboard)
Pfeil 10.25.1 Clipboard-Objekte
Pfeil 10.25.2 Mit Transferable auf den Inhalt zugreifen
Pfeil 10.25.3 DataFlavor ist das Format der Daten in der Zwischenablage
Pfeil 10.25.4 Einfügungen in der Zwischenablage erkennen
Pfeil 10.25.5 Drag & Drop
Pfeil 10.26 Undo durchführen *
Pfeil 10.27 AWT, Swing und die Threads
Pfeil 10.27.1 Ereignisschlange (EventQueue) und AWT-Event-Thread
Pfeil 10.27.2 Swing ist nicht threadsicher
Pfeil 10.27.3 invokeLater(…) und invokeAndWait(…)
Pfeil 10.27.4 SwingWorker
Pfeil 10.27.5 Eigene Ereignisse in die Queue setzen *
Pfeil 10.27.6 Auf alle Ereignisse hören *
Pfeil 10.28 Barrierefreiheit mit der Java Accessibility API
Pfeil 10.29 Zeitliches Ausführen mit dem javax.swing.Timer
Pfeil 10.30 Die Zusatzkomponentenbibliothek SwingX
Pfeil 10.30.1 Im Angebot: Erweiterte und neue Swing-Komponenten
Pfeil 10.30.2 Überblick über erweiterte Standard-Swing-Klassen
Pfeil 10.30.3 Neue Swing-Klassen
Pfeil 10.30.4 Weitere SwingX-Klassen
Pfeil 10.30.5 SwingX-Installation
Pfeil 10.31 Zum Weiterlesen
 
Zum Seitenanfang

10.27AWT, Swing und die Threads Zur vorigen ÜberschriftZur nächsten Überschrift

Swing nutzt für Zeichenoperationen und das Abarbeiten von Ereignis-Programmcode einen eigenen Thread. Die folgenden Abschnitte erklären, warum Swing einen eigenen Thread nutzt und welche Konsequenzen das für den Entwickler hat.

 
Zum Seitenanfang

10.27.1Ereignisschlange (EventQueue) und AWT-Event-Thread Zur vorigen ÜberschriftZur nächsten Überschrift

Der Benutzer erzeugt bei seiner Arbeit mit der Oberfläche Ereignisse. Diese werden entweder von den Peer-Objekten oder von Klassen der Applikation erzeugt. Bevor sie vom eigenen Programm bearbeitet werden, gelangen sie in eine Ereignisschlange (engl. event queue). Jedem Fenster ist eine eigene Event-Queue zugeordnet. Diese Event-Queue ist für Programmierer zugänglich und in einer plattformunabhängigen Klasse EventQueue implementiert. Elemente der Klasse sind Objekte vom Typ AWTEvent. Ein eigener Thread, der AWT-Event-Thread, läuft parallel zur Anwendung und arbeitet die angesammelten Ereignisse dieser Warteschlange ab.

Der AWT-Thread führt auch den Programmcode in den Listenern aus. Aus diesem Grund ist es ungünstig, in einen Event-Handler lang dauernden Programmcode zu legen, denn dann »steht« die grafische Applikation und lässt sich nicht fortsetzen, weil der AWT-Thread blockiert ist. Bei einer längeren Aktion in einem Event-Handler sollten wir einen separaten Thread starten, damit die grafische Oberfläche sofort wieder reaktionsfähig ist.

[zB]Beispiel

Wenn eine Schaltfläche angeklickt wird, soll ein langer Text in den Puffer eingelesen werden:

ActionListener al = new ActionListener() {
@Override public void actionPerformed( ActionEvent e ) {
new Thread( new ReaderThread(e.getActionCommand()) ).start();
}
};

In einer externen Klasse lesen wir zum Beispiel einen Text:

class ReaderThread implements Runnable {
ReaderThread( String actionCommand ) {
// ...
}
public void run() {
// ...
}
}

Eine Alternative ist der SwingWorker, den wir später in Abschnitt 10.27.4, »SwingWorker«,
vorstellen.

Unter dem AWT ist es kein Problem, wenn zwei Threads auf ein und dasselbe Oberflächenelement zugreifen. Bei Swing ist dies jedoch etwas anders, wie wir im nächsten Abschnitt sehen werden.

 
Zum Seitenanfang

10.27.2Swing ist nicht threadsicher Zur vorigen ÜberschriftZur nächsten Überschrift

Die Tatsache, dass das Swing-Toolkit nicht threadsicher ist, erstaunt vielleicht auf den ersten Blick. Das AWT ist threadsicher, da AWT auf Plattform-Peer-Elemente vertraut. In einer List-Box unter dem AWT ist es problemlos möglich, ein Element einzufügen und parallel zu löschen. Doch auf die Synchronisation bei Swing wurde aus zwei Gründen verzichtet:

  • Operationen können in Threads zu ärgerlichen Deadlock-Situationen führen.

  • Der Verzicht auf Synchronisation kann die Ausführungsgeschwindigkeit erhöhen.

[»]Hinweis

Gibt es konkurrierende Zugriffe auf Swing-Komponenten, kann es zu Exceptions der Art »Exception in thread "AWT-EventQueue-0"« kommen.

Swing weiß mit konkurrierenden Zugriffen nicht allzu viel anzufangen

In einem kleinen Beispiel wollen wir genau einen Fehler provozieren, in dem zwei Threads gleichzeitig eine Datenstruktur modifizieren und somit Swing aus dem Takt werfen. Es ist ein mahnendes Beispiel, Operationen an GUI-Komponenten nur über den AWT-Event-Thread vorzunehmen:

Listing 10.90com/tutego/insel/ui/swing/SwingNoSyncDemo.java, main()

final DefaultListModel<String> model = new DefaultListModel<>();

JFrame frame = new JFrame();
frame.add( new JList<>( model ) );
frame.setSize( 200, 100 );
frame.setVisible( true );

new Thread() {
@Override public void run() {
setPriority( Thread.MIN_PRIORITY );
while ( true )
model.addElement( "Dumm gelaufen" );
}
}.start();

new Thread() {
@Override public void run() {
setPriority( Thread.MIN_PRIORITY );
while ( true )
model.removeElement( "Dumm gelaufen" );
}
}.start();

Werfen wir einen Blick auf die Ausgabe, die erscheint, wenn das Programm nur kurz läuft:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10911
at javax.swing.plaf.basic.BasicListUI.updateLayoutState(BasicListUI.java:1368)
...
at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException

Obwohl das DefaultListModel als unterliegende Datenstruktur den Vector nimmt und dieser nur synchronisierte Methoden besitzt, die beim nebenläufigen Zugriff den Vector nicht irritieren, ist er nicht der Übeltäter. Es liegt an Swing, wie mit den Daten umgegangen wird. Wenn der erste Thread Daten in das Model einfügt, muss die Visualisierung aktualisiert werden. Wir wissen von DefaultListModel, dass es über ListDataEvent das Darstellungsobjekt informiert, wenn es den Inhalt neu zeichnen muss. Merken wir uns die Stelle. Das Darstellungsobjekt wird sich nun vom Model die Daten besorgen. Bis dahin läuft alles ganz gut. Doch der zweite Thread löscht parallel die Daten aus dem Model. Springen wir jetzt zur Markierung zurück. Irgendwann passiert es, dass zwischen der Benachrichtigung der Darstellungskomponente und dem wirklichen Zeichnen sowie der Anfrage an das Model etwas gelöscht wird. Die Visualisierung weiß davon aber nichts und versucht, alle Werte zu zeichnen; es fehlt jedoch mindestens ein Wert. Daher folgt eine ArrayIndexOutOfBoundsException in der Methode elementAt(…) vom Vector. Die Visualisierung fragt mit einem Index im Vector nach, doch der Vector hat vom Lösch-Thread schon ein Element abgeben müssen. Daher ist die interne Größe des Vektors kleiner als der von Swing erfragte Index.

Erlaubte Methoden

Einige der Methoden sind threadsicher und dürfen von beliebigen anderen Threads aufgerufen werden:

  • der Aufruf zum Neuzeichnen mit repaint() oder revalidate() für die Größenänderung einer Komponente im Container

  • alle Aufrufe auf neuen Komponenten, die noch nicht etwa mit setVisible(boolean) (früher show()) bzw. pack() veröffentlicht wurden

  • Die Eintragung von Listenern, etwa bei JComponent mit den Methoden addPropertyChangeListener(…), removePropertyChangeListener(…) und addVetoableChangeListener(…), removeVetoableChangeListener(…) ist sicher.

  • Bei JCheckBoxMenuItem ist es dann die einsame Methode setState(boolean), die synchronisiert ist. Es findet sich intern mal hier, mal da ein synchronisierter Block.

Ansonsten ist jedoch nicht viel dabei, und wir müssen unsere Teile synchronisiert ausführen. Um Programmstücke konform ausführen zu lassen, definiert Swing einige Methoden und Klassen. Dazu gehören:

  • invokeLater(Runnable)

  • invokeAndWait(Runnable)

  • JProgressBar

  • ProgressMonitor

  • ProgressMonitorInputStream

  • SwingWorker

 
Zum Seitenanfang

10.27.3invokeLater(…) und invokeAndWait(…) Zur vorigen ÜberschriftZur nächsten Überschrift

Da Swing nicht threadsicher ist, bietet der AWT-Thread die einzige Möglichkeit zur Manipulation von Oberflächenelementen. Wenn wir es schaffen, dort die Aufträge einzureihen, dann wird nichts schiefgehen. Genau für diese Aufgabe gibt es in der Klasse EventQueue zwei statische Methoden: invokeLater(Runnable) und invokeAndWait(Runnable). Damit lassen sich beliebige Programmstücke in die Warteschlange einführen. In der Warteschlange für das AWT liegen Aufträge und Ereignisse, die an die Oberflächenelemente verteilt werden. Alles spielt sich dabei neben dem Haupt-Thread ab, sodass Parallelität herrscht. Hat die Warteschlange alle Ereignisbehandler aufgerufen, kann der Programmcode von invokeLater(…) und invokeAndWait(…) durchlaufen werden.

Die beiden Methoden erfüllen unterschiedliche Bedürfnisse:

  • invokeLater(…) legt einen Runnable in die Warteschlange und kehrt sofort zurück. Die Funktion ist somit asynchron. Der Aufrufer weiß nicht, wann der Programmcode abgearbeitet wird.

  • invokeAndWait(…) legt ebenfalls einen Runnable in die Warteschlange, verharrt aber so lange in der Funktion, bis der Programmcode in run() aufgerufen wurde. Die Funktion ist also synchron.

Mit diesen statischen Methoden lassen sich jetzt alle Manipulationen an der Oberfläche durchführen. Den statischen Methoden wird ein Runnable-Objekt übergeben, das den Programmcode repräsentiert, der im AWT-Event-Thread auszuführen ist.

[zB]Beispiel

Ein Fortschrittsbalken JProgressBar mit dem Namen bar soll aus einem Nicht-AWT-Event-Thread einen Wert gesetzt bekommen:

EventQueue.invokeLater( new Runnable() {
@Override public void run() {
bar.setValue( i );
}
} );

Bei der Auswahl der beiden Methoden haben wir uns für den Fortschrittsbalken für invokeLater(…) entschieden. Es ist in der Regel wenig sinnvoll, die Methode so lange stehen zu lassen, bis die Anzeige auch wirklich gezeichnet wurde.

Ein Problem stellt für sehr viele Applikationen leider die Tatsache dar, dass das Objekt zur Manipulation immer irgendwie sichtbar sein muss. Hier soll bar einfach direkt für die innere Klasse sichtbar sein.

Die Methoden invokeLater(…) und invokeAndWait(…) befinden sich nicht nur in der Klasse EventQueue, sondern sind noch einmal in der Klasse SwingUtilities untergebracht. Daher ist es gleichgültig, ob wir EventQueue.invokeXXX(…) oder SwingUtilities.invokeXXX(…) schreiben. SwingUtilities hat vielleicht den Vorteil, dass das Paket java.awt für die EventQueue nicht importiert werden muss, sonst gibt es aber keinen Unterschied.

[»]Hinweis

Einige Entwickler setzen den Programmcode der main(String[])-Methode zum Aufbau eines JFrames ebenfalls in einen invokeLater(…)-Block, etwa so:

SwingUtilities.invokeLater( new Runnable() {
@Override public void run() {
JFrame f = new JFrame( "Uhrzeit" );
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.add( new JLabel( String.format( "%tT", new Date() ) ) );
f.setSize( 250, 100 );
f.setVisible( true );
}
} );

Obwohl ein new JFrame() schon den AWT-Event-Thread startet, muss erst ab der Programmzeile mit setVisible(…) alles abgesichert werden. Die Beispiele in diesem Buch sind also vom Standpunkt des AWT-Threadings aus völlig in Ordnung.

Implementierung *

Genehmigen wir uns abschließend noch einen kurzen Blick auf die Implementierung. Es lässt sich schon erahnen, dass invokeLater(…) einfacher ist:

public static void invokeLater( Runnable runnable ) {
Toolkit.getEventQueue().postEvent(
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable) );
}

Das Ereignis, das in die Event-Queue kommt, ist vom Typ InvocationEvent und damit ein AWTEvent. Wir übergeben unser Runnable-Objekt, damit der AWT-Thread später die run()-Methode aufrufen kann.

Die statische Methode invokeAndWait(…) ist etwas komplizierter; wir wollen von der Implementierung nur wenige Zeilen betrachten. Im Prinzip leistet die Methode das Gleiche wie invokeLater(…); auch sie muss das InvocationEvent in die Warteschlange legen. Hinzu kommt jedoch, dass invokeAndWait(…) auf das Ende des Threads warten muss:

InvocationEvent event = new InvocationEvent(
Toolkit.getDefaultToolkit(), runnable, lock, true);
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait();
}

Das konstruierte InvocationEvent bekommt als Argument wieder das runnable. Jetzt erhält es aber zusätzlich ein Lock-Objekt. Wenn der AWT-Thread durch die Ereignis-Warteschlange geht und das InvocationEvent sieht, führt er wieder die run()-Methode aus. Anschließend informiert er über notify() das wartende Objekt. Dann steigt invokeAndWait(…) aus dem synchronized-Block aus, und es geht weiter.

 
Zum Seitenanfang

10.27.4SwingWorker Zur vorigen ÜberschriftZur nächsten Überschrift

Mit der Klasse SwingWorker ist es einfach möglich, längere Programmteile im Hintergrund von einem Nicht-AWT-Thread abarbeiten zu lassen und dann später die Ergebnisse über den AWT-Thread wieder in das GUI einfließen zu lassen.

Für einen eigenen SwingWorker ist zunächst eine Unterklasse von javax.swing.SwingWorker zu bilden. Wir wollen eine Klasse ClockPrecision angeben, die zwei Sekunden wartet und dabei die Zeit misst – das Ergebnis ist durch Ungenauigkeit nicht wirklich zwei Sekunden. Wir interessieren uns hier für die Ungenauigkeit. Nach Ablauf der Zeit soll der SwingWorker das Ergebnis auf die Schaltfläche schreiben, die auch der Auslöser für die Warterei ist:

Listing 10.91com/tutego/insel/ui/event/SwingWorkerDemo.java

package com.tutego.insel.ui.event;

import java.awt.event.*;
import javax.swing.*;

public class SwingWorkerDemo extends JFrame {

private JButton button = new JButton( "Change my mind!" );

SwingWorkerDemo() {
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
add( button );

ActionListener al = new ActionListener() {
@Override public void actionPerformed( ActionEvent e ) {
new ClockPrecision().execute();
}
};

button.addActionListener( al );

pack();
}

class ClockPrecision extends SwingWorker<Long,Object> {
@Override public Long doInBackground() {
long startNano = System.nanoTime();
try { TimeUnit.SECONDS.sleep( 2 ); } catch ( InterruptedException e ) { }
return (System.nanoTime() – startNano ) / (1000*1000);
}

@Override protected void done() {
try {
button.setText( "" + get() );
}
catch ( InterruptedException | ExecutionException e ) { e.printStackTrace(); }
}
}

public static void main( String[] args ) {
new SwingWorkerDemo().setVisible( true );
}
}

Die Methode done() bekommt die Rückgabe von doInBackground() über die get()-Methode. Unser SwingWorker durchläuft mehrere Phasen, an denen wir uns durch Überschreiben einiger Methoden aktiv beteiligen:

  • Es beginnt mit execute(), was den SwingWorker dazu bewegt, einen so genannten Worker-Thread aufzubauen.

  • Der Worker-Thread ruft doInBackground() auf, in den wir unseren im Hintergrund auszuführenden Programmteil setzen. Der Rückgabetyp ist durch die generische Verwendung frei wählbar. Da SwingWorker auch vom Typ Future ist, kann das Ergebnis einer Berechnung get() liefern. Sind mit addPropertyChangeListener(…) neue PropertyChangeListeners angemeldet, können wir sie mit firePropertyChange(…) aufrufen und während der Verarbeitung Statusereignisse schicken. publish(V...) erlaubt das Absenden von Zwischenergebnissen, die sich unter dem AWT-Event in process(List<V>) verarbeiten lassen. Dieser Typ kann ein anderer als der von get() sein, und so bestimmt die zweite Typvariable der generischen Klasse diesen Typ.

  • Am Ende des Worker-Threads kommt es im AWT-Event-Thread zu einem Aufruf von done(), wo wir unsere Swing-Operationen vornehmen können.

Weiteres ist der API-Dokumentation zu entnehmen.

 
Zum Seitenanfang

10.27.5Eigene Ereignisse in die Queue setzen * Zur vorigen ÜberschriftZur nächsten Überschrift

Es ist ohne großen Umweg möglich, eigene Ereignisse zu erzeugen und in der EventQueue zu platzieren. Damit lassen sich beispielsweise Eingaben des Benutzers emulieren. Da alle Ereignisse von Komponenten von AWTEvent erben, lässt sich ein ActionEvent erzeugen, das dann wiederum von einem interessierten Listener entgegengenommen wird. Jetzt fehlt uns nur noch eine Methode, die Ereignisse in die Schlange setzt. Dazu bietet die Klasse EventQueue die Methode postEvent(AWTEvent) an. Im Beispiel sehen wir die notwendigen Aufrufe, um beginnend bei Toolkit an die SystemEventQueue zu kommen:

Toolkit.getDefaultToolkit().getSystemEventQueue().
postEvent(
new ActionEvent( /* Object source, int id, String command */ )
);
class java.awt.Toolkit
  • final EventQueue getSystemEventQueue()
    Liefert ein Exemplar der EventQueue für eine Applikation oder ein Applet. Eine SecurityException wird ausgelöst, falls der Security-Manager den Zugriff auf EventQueue verbietet.

class java.awt.EventQueue
  • void postEvent(AWTEvent theEvent)
    Legt ein Ereignis in die EventQueue. Danach werden vorhandene EventQueueListener und notifyEventQueueListener aufgerufen.

Einer Komponente ein Ereignis schicken

Ist die Komponente bekannt, der ein Ereignis geschickt werden soll, lässt sich die Component-Methode dispatchEvent(AWTEvent e) verwenden. Sie sendet ein AWTEvent – die Basisklasse aller AWT-Ereignisse – an die Komponente, womit alle Listener aufgerufen werden. Für die Aktivierung einer Schaltfläche b lautet es dann:

b.dispatchEvent( new ActionEvent(b,ActionEvent.ACTION_PERFORMED, "text") );
 
Zum Seitenanfang

10.27.6Auf alle Ereignisse hören * Zur vorigen ÜberschriftZur nächsten Überschrift

Um keine Ereignisse zu versäumen, lässt sich über das Toolkit ein Super-Listener anmelden. Dieser Listener ist vom Typ AWTEventListener, der über addAWTEventListener(…) mit dem Toolkit verbunden wird:

AWTEventListener ael = new AWTEventListener() {
@Override public void eventDispatched( AWTEvent event ) { (…)
}
};
Toolkit.getDefaultToolkit().addAWTEventListener( ael, mask );

Die mask bestimmt den Typ eines jeden gemeldeten AWTEvent. Hier kann für Mausbewegungen etwa AWTEvent.MOUSE_MOTION_EVENT_MASK stehen.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern