Zur Erinnerung die bereits besprochenen und noch geplanten Themen hier noch eine Auflistung selbiger:
- Teil 1: Einführung – enthält ein erstes Hello Swing, sowie eine Erklärung der Aufgabenstellung
- Teil 2: Der GUI Prototyp – wir basteln einen Prototypen, der StandbyScreen (JLabel, BorderLayout)
- Teil 3: Der GUI Prototyp – wir basteln weiter am Prototypen, die Datenanzeige (BoxLayout, JTextField)
- Teil 4: Interaktion mit der GUI – der Prototyp erwacht zum Leben
- Teil 5: Hinter der GUI rattert es – Threadsicherheit ist das Thema dieser Lektion
Nachdem wir nun erfolgreich eine GUI gebaut haben, die auf unsere ersten Klicks reagiert wollen wir uns nun mit der Nebenläufigkeit in Swing Anwendungen beschäftigen.
Aufgabe aus Teil 4
Aus Teil 4 war noch ein ActionListener für den Menüpunkt beenden zu realisieren.
Action Listener
Wir erstellen analog zum EditActionListener eine neue Klasse MenuActionListener. In dieser prüfen wir ob das Event dass der Listener enthält das Beenden Event ist, schließen erst das JFrame und dann die ganze Anwendung.
package at.nullpointer.guiprototype.listener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import at.nullpointer.guiprototype.Prototype; public class MenuActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { if(e.getActionCommand().equals("Beenden")){ Prototype.getJFrame().dispose(); System.exit(0); } } }
Den ActionListener müssen wir nun nur noch dem MenuItem zuweisen. Dies geschieht analog zu der Zuweisung beim JButton. Wir editieren dazu die Klasse PrototypeMenuBar
close.addActionListener(new MenuActionListener());
Damit können wir nun das Programm über den Menüpunkt beenden. Auch das Tastenkürzel ALT+B führt zum Programmende.
NebenLäufigkeit in Swing
Die erste Form von Nebenläufigkeit in Swing haben wir bereits in den vorherigen Teilen dieser Serie kennengelernt. Der Event-Dispatcher Thread wurde bereits genutzt um die GUI zu erstellen und anzuzeigen
//Schedule a job for the event-dispatching thread: //creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } });
Dabei wird im Initial-Thread, der die main Methode ausführt, oben benannter Code ausgeführt. Man übergibt dem Event-Dispatcher Thread ein Runnable Objekt, dass dieser ausführt sobald er soweit ist. Bei invokeLater arbeitet der Initialthread nach der Übergabe gleich weiter und würde nachfolgenden Code behandeln.
Für den Fall, dass der nachfolgende Code erst ausgeführt werden darf, wenn die GUI erzeugt wurde gibt es noch die invokeAndWait Methode, die das Runnable Objekt ebenfalls übergibt, aber auf dessen Beendung wartet.
Führt man seine GUI nicht im Event-Dispatcher Thread aus funktioniert sie meist auch, es kann aber zu Speicherverletzungen und somit Fehlverhalten kommen, welche nur schwer zu finden bzw. korrigieren ist. Von diesem Event-Dispatcher Thread ist jedoch die gesamte Swing Oberfläche abhängig, da die meisten Komponenten nicht Thread Safe implementiert sind. Deshalb sollten darauf nur kurze Tasks, wie das feuern von Events, oder z.B. minimale Textkorrekturen ausgeführt werden (zB durch zusätzliche invokeLater Aufrufe) um ein Einfrieren der Applikation zu vermeiden. Ein Umstand dem wir in den bisherigen Teilen dieses Tutorials kaum Rechnung getragen haben.
Für rechenintensivere Aufgaben, oder Tasks die zB Netzwerkkommunikation erfordern ist es daher notwendig auf eine andere Abwicklung zurückzugreifen. Sogenannte Worker-Threads werden für die Umsetzung dessen verwendet. Man muss dazu mit seinem Objekt die abstrakte Klasse SwingWorker implementieren, welche einige Features zur Kommunikation mit dem Event-Dispatcher Thread beinhaltet.
Akuell weist unser Prototyp folgendes Verhalten auf: Wenn wir in unserem Prototypen auf der EditView auf OK klicken übermittelt unser Programm die Daten an die Enterprise Software im Hintergrund. Ist diese mit dem Bearbeiten fertig, übersendet sie uns ein OK, welches wir bestätigen müssen. Erst dann schaltet unser Prototyp in den Anzeigemodus. Verzögert sich nun das Absenden der Bestätigung friert unser Programm ein. Dies kann man leicht nachstellen indem man die Mock-Klasse MockCompanySoftware um z.B. eine fette Schleife erweitert.
public String setKundendaten(Kundendaten kdata) { for (int x = 0; x < 100000; x++) for (int y = 0; y < 100000; y++){ System.currentTimeMillis(); } return "Daten gesandt"; }
Wir müssen nun merklich warten bis unser Programm weiter verwendbar ist. Minimieren und verschieben funktioniert immerhin. Doch der Button bleibt gedrückt, die Ansicht ebenfalls auf der EditView. Um dem zu begegnen müssen wir die Prototype#sendData Methode ändern. Dazu erzeugen wir einen SwingWorker, der das Senden der Daten für uns übernimmt.
public static void sendData() { SwingWorker worker = new SwingWorker<Void , Void>() { private String answer; // Die eigentliche Aufgabe wird bearbeitet @Override protected Void doInBackground() throws Exception { MockCompanySoftware mcs = new MockCompanySoftware(); answer = mcs.setKundendaten(null); return null; } /* Wenn die Aufgabe fertig ist wird unsere JOptionPane angezeigt Dazu wird diese Methode aufgerufen wenn der Event-Dispatcher-Thread bemerkt, dass der HintergrundThread abgearbeitet ist. */ @Override public void done() { JOptionPane.showMessageDialog(null, answer); } }; //Der Worker wird ausgeführt worker.execute(); }
Hier sehen wir den Aufbau des SwingWorker. Er beinhaltet eine doInBackground Methode, die in einem Background-Thread ausgeführt wird. Sobald dieser Fertig ist wird vom Event-Dispatcher-Thread die done Methode aufgerufen. Mit der execute Methode startet man den Background-Thread. Nach erfolgreiches Event könnte von dem Ergebnis mittels get Methode gebrauch machen.
Probiert den Prototypen nun nochmal aus, der Button wird nun freigegeben.
Damit haben wir unsere Applikation nebenläufig gemacht und ich beschließe diese Tutorial-Reihe mit den Worten:
Wenn ihr euer Wissen um Swing erweitern und effektiv einsetzen wollt, setzt euch am besten gleich hin und programmiert, schaut euch fremden Code z.B. auf Open Sourceplattformen an und programmiert dann weiter. Vielleicht baut ihr ja sogar das Beispiel hier aus. Weitere Anregungen oder Fragen dazu sind natürlich gern gesehen.
Zum Weiterlesen ein paar Buchtipps, sowie Weblinks. Swing wird neben den online Tutorials und spezialisierten Büchern ebenfalls in div. Standardlehrbüchern zu Java behandelt.
Trail: Creating a GUI With JFC/Swing – von Oracle: http://download.oracle.com/javase/tutorial/uiswing/index.html
The JFC Swing Tutorial – Addison-Wesley Verlag 2004 Verlag – ISBN 0201914670, 9780201914672
http://books.google.at/books?id=3rWTX-vjUhEC
Für Fortgeschrittene: The definitive guide to Java Swing – Apress Verlag 2005 – ISBN 1590594479, 9781590594476
http://books.google.at/books?id=YPjZNlEgAMcC
Schreibe einen Kommentar