2010-08-12 8 views
6

Dies ist für die Swing-Experten da draußen. Ich habe viel Zeit mit diesem Problem verbracht, daher brauche ich ein paar Zeilen, um das Problem zu erklären.Java Swing Fortschrittsbalken von EDT Problem

Ich habe eine eigenständige Java Swing-Anwendung (Java 6). In meiner Anwendung habe ich einen Rahmen mit einer Optionsfeldgruppe. Ich habe eine einzige Aktion mit allen Knöpfen in der Gruppe verbunden. Die Aktion prüft, um zu sehen, welcher Radiobutton ausgewählt ist und einige Arbeiten ausführt. Die "Arbeit" beinhaltet etwas Hintergrundberechnung sowie etwas Malen in zwei anderen Rahmen in meiner Anwendung. Die Hintergrundberechnung ist Multi-Threading.

Ich möchte eine Fortschrittsanzeige anzeigen, wenn der Benutzer einen der Optionsfelder auswählt. Wenn jedoch eine Optionsschaltfläche ausgewählt ist, wird während der Aktion für die Optionsschaltfläche die Fortschrittsanzeige nicht angezeigt. Ich habe versucht, jdialog Typ Fortschrittsbalken, Glasscheiben, etc. Keine von ihnen erscheinen, bis die "Arbeit" abgeschlossen ist. Dies scheint zu sein, weil Swing das Radio-Button nicht fertig bearbeitet, bis die "Arbeit" in der entsprechenden Aktion abgeschlossen ist. Und da der EDT nur eine Sache nach der anderen ausführt, wird der Fortschrittsbalken-Dialog (oder die Glasscheibe) niemals angezeigt.

Ich habe dann versucht, einen SwingWorker zu verwenden, all diese "Arbeit" zu tun. Starten Sie den Fortschrittsbalken (oder aktivieren Sie eine Glasscheibe), starten Sie den SwingWorker und schließen Sie den Fortschrittsbalken (oder deaktivieren Sie die Glasscheibe) in der Methode done() für den SwingWorker. Dies scheint den Fortschrittsbalken in Ordnung zu bringen, aber das Gemälde, das Teil der "Arbeit" ist, wird manchmal nicht vollständig ausgeführt, was mich mit einigen Bildartefakten belässt (die paintComponent-Methode ist ziemlich kompliziert, möchte also hier nicht reproduzieren). Die Artefakte verschwinden, wenn ich die Größe des Fensters ändere. In der Tat passiert das, wenn ich eine Klasse verwende, die Thread statt SwingWorker auch erweitert. Das ist alles, weil Swing nicht threadsicher ist und ich versuche GUI-Arbeit von einem anderen Thread als dem EDT zu machen. Ich verstehe diesen Teil.

Was mache ich? "Arbeit" dauert ungefähr 30 Sekunden und das scheint zu lang zu sein, ohne dem Benutzer irgendeine Art von Hinweis zu geben, dass das Programm funktioniert. Ich habe auch versucht, den Cursor zu einem Wartecursor zu ändern und habe auf die gleichen Probleme wie oben gerannt. Die einzige Sache, die ich tun kann, ist den Rahmen zu deaktivieren und den Titel des Rahmens auf etwas Text wie "arbeiten ..."

Dieses Problem hat jemand zuvor gesehen?

Antwort

4

Ich denke, du hast recht, die Arbeit im SwingWorker-Thread zu machen, aber du solltest nicht versuchen, dort zu malen.

Ich würde zu geneigt sein:

  • Haben die Action show() den Fortschrittsbalken, auf den Weg der Swingworker dann verlassen

  • Haben der Arbeiter-Thread die Arbeit, und in regelmäßigen Abständen rufen Repaint() auf der Fortschrittsbalkenkomponente (dies ist garantiert threadsicher)

  • Fortschrittsbalken hat seine eigene paintComponent (die automatisch auf dem EDT aufgerufen wird). Bei Bedarf kann dies eine Variable lesen, die vom Worker-Thread aktualisiert wird, um den Fortschritt zu messen.

  • Wenn der Worker-Thread beendet ist, rufen Sie invokeLater() auf, um eine abschließende Close-Down-Funktion auf dem EDT auszuführen, die den Befehl ausblendet Fortschrittsbalken und tun andere GUI-bezogene Bereinigung/zeigen eine Abschlussmeldung an den Benutzer usw.

+0

Wie stelle ich sicher, dass der EDT kein anderes Bild malt, bis die Arbeit am SwingWorker-Thread abgeschlossen ist? Die Arbeit, die im Hintergrund ausgeführt werden kann, muss abgeschlossen sein, bevor meine Bilder erneut gemalt werden. – Anu

+0

Vielen Dank! Ich habe das zur Arbeit bekommen. – Anu

4

Als Sie die Arbeit vom EDT zum Swing Worker verlagert haben (was das Richtige war), klingt es, als ob sowohl die Arbeit als auch das Gemälde zum Swing Worker bewegt würden. Das Gemälde sollte immer noch auf dem EDT passieren. Sie können dies erreichen, indem Sie SwingUtilities.invokeLater verwenden, um ein Repaint aus dem Hintergrundthread aufzurufen, oder indem Sie die SwingWorker.publish(V...) verwenden, die Benachrichtigungen von Ihrem Arbeitsthread erhält und sie über die Template-Methode SwingWorker.process(V...) (die Sie überschreiben) auf dem EDT verfügbar macht. Ihr process Override kann die Zwischenbenachrichtigungen verarbeiten, indem ein Teil des Bildschirms neu gezeichnet wird, der Fortschritt aktualisiert wird oder andere geeignete Maßnahmen ergriffen werden. Alle hier vorgenommenen Änderungen der Benutzeroberfläche werden sichtbar, ohne dass der Rest der Arbeit abgeschlossen werden muss.

+0

Dank bekam ich Mikera-Lösung zu arbeiten, aber Ihre Kommentare über das Gemälde an den EDT die auch angespornt bewegt hat So habe ich Dinge verändert! – Anu

+0

Die Verwendung von SwingWorker.publish() auf dem Arbeitsthread ist der Weg zu gehen, denke ich. – keuleJ