HOWTO: GUI mit Swing – Teil 5: Concurrency in Swing

Wie entwickelt man eigentlich eine GUI mit Java Swing? Eine mehrteilige Einführung in dieses Thema. Teil 5 beschäftigt sich mit Nebenläufigen prozessen in Swing


Zur Erinnerung die bereits besprochenen und noch geplanten Themen hier noch eine Auflistung selbiger:

      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

      Aufgabe überspringen

      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

      Ähnliche Artikel:

      Autor: Thomas Pummer

      Thomas Pummer ist Softwareentwickler an der Universität Wien. In seiner Freizeit betreut er das Open Source Projekt TrayRSS und werkt an diversen anderen kleinen Projekten. Er ist sehr interessiert an Open Source und Webentwicklung und testet gern neue Programmiersprachen.

      2 Gedanken zu „HOWTO: GUI mit Swing – Teil 5: Concurrency in Swing“

      Schreibe einen Kommentar

      Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

      *