# Bug; Swing-Worker, Progressbar und Mouse



## Milbo (1. Nov 2007)

Hmm also wie erkläre ich am besten mein Problem:

In meinem Programm werden eine Menge Daten über eine Swingoberfläche eingegeben. Die Swingoberfläche startet "leer", dass heisst es wird nur der Rahmen erzeugt mit JMenus oben drin bzw Icons (wie beim Programm jsmooth z.B.). Wenn ich jetzt auf "Neu" gehe oder auf "Datei öffnen" dann wird die Oberfläche im Inneren erzeugt. Damit der Anwender sieht, dass er was gedrückt hat und ne Vorstellung hat wie lange das erstellen noch dauert habe ich eine Progressbar eingebaut (Swing-Worker halt).

Dabei fliegt mir folgende Exception, wenn ich die Maus innerhalb des Swingfensters bewege.

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0
	at javax.swing.plaf.basic.BasicTabbedPaneUI.tabForCoordinate(Unknown Source)
	at javax.swing.plaf.basic.BasicTabbedPaneUI.setRolloverTab(Unknown Source)
	at javax.swing.plaf.basic.BasicTabbedPaneUI.access$2000(Unknown Source)
	at javax.swing.plaf.basic.BasicTabbedPaneUI$Handler.mouseMoved(Unknown Source)
	at java.awt.Component.processMouseMotionEvent(Unknown Source)
	at javax.swing.JComponent.processMouseMotionEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)


Ich kann den ganzen Code leider nicht posten, da es erstens mehr als 1000 Zeilen code (ohne Kommentar oder Leerzeilen) sind und zweitens Closed Source.

Starten tue ich das ganze so:

```
try {			
	task = new ThreadDatenBlatterstellung(myDBs, oeffnen);	
	task.addPropertyChangeListener(this);
	task.execute();
} catch (Exception e) {
	System.out.println("DatenBlatterstellung wirft Exception: "+e);
}

try {
	task.get();
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (ExecutionException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
}
```


Wenn ich das task.get weglasse, dann fliegt oben genannte Exception, weil er anscheinend versucht die Swing-Komponenten anzusprechen bzw zu bestimmen, obwohl die ja gerade erst erstellt werden. Dafür läuft die Progressbar wie gewünscht.

Wenn ich das task.get einbaue, dann fliegt keine Exception mehr, aber die Progressbar wird dann zum Schluss abgearbeitet und springt von 0 auf 100 und is wieder weg. Anscheinend lässt dann der Swingworker nur den ThreadDatenBlatterstellung ablaufen. Dann kann ich das ganze ja gleich ohne Swingworker machen. Hmmm

Ich suche letzendlich nach einer Möglichkeit, wie ich der Maus was zu fressen geben kann (lol) oder wie ich sie abschalten kann für die Dauer des Auftrags.

Ich fummle an dem Problem schon seit mehreren Monaten rum. Die Exception ist zwar nicht so schlimm, weil der Rest gewohnt weiterläuft, da aber bald die Veröffentlichung meines Programmes ansteht, will ich das endlich beseitigen. Habe auch bereits mit anderen Javaproggern daran gesessen. Wir haben es nicht geschafft eine Lösung zu finden. Also ihr seit meine letzte Hoffnung.

hoffnungsvolle Grüße 
Milbo


----------



## Wildcard (1. Nov 2007)

Was macht der Task denn?


----------



## Guest (1. Nov 2007)

Eine Möglichkeit ist GlassPane und das Abfangen der Mouse-Events darin.
Das lässt sich sogar mit einem Effekt kombinieren, bei dem das Hauptfenster etwas gedimmt erscheint und
die Progressbar schön in der Mitte des Fensters angezeigt wird.

Beispiele zu GlassPane findest du hier: http://www.java2s.com/Code/Java/Swing-JFC/GlassPane.htm


----------



## Milbo (1. Nov 2007)

Wildcard hat gesagt.:
			
		

> Was macht der Task denn?



Ich versuche mal es etwas zu erklären.

Es wird eine JTabbedPane aufgbaut und darin Panels und Labels, Knöpfe, Checkboxen. Verschiedenste Swing-Komponenten eben.

Es müsste eigentlich auch ein generelles Problem sein und ist glaube ich mit dem richtigen Wissen sehr einfach zu umgehen, sowas wie Maus abschalten, oder der Glasspane des Hauptfensters sagen, dass sie alle Mausevents abfangen soll oder so. Hab ich natürlich probiert, aber nicht hinbekommen.

Mfg Milbo
[/code]


----------



## Milbo (1. Nov 2007)

Anonymous hat gesagt.:
			
		

> Eine Möglichkeit ist GlassPane und das Abfangen der Mouse-Events darin.
> Das lässt sich sogar mit einem Effekt kombinieren, bei dem das Hauptfenster etwas gedimmt erscheint und
> die Progressbar schön in der Mitte des Fensters angezeigt wird.
> 
> Beispiele zu GlassPane findest du hier: http://www.java2s.com/Code/Java/Swing-JFC/GlassPane.htm



haha, das sieht gut aus, das werde ich jetzt probieren, weil ich dachte mir schon, dass die Lösung so in der Art aussehen muß. Ich denke mal so muß es gehen. Vielen Dank, werds nach dem Mittagessen ausprobieren.

Herzliche Grüße 
Milbo


----------



## Wildcard (1. Nov 2007)

Im Background Thread darfst du die GUI *nicht* manipulieren. Swing ist nicht threadsicher!


----------



## Milbo (1. Nov 2007)

Mir ist klar das Swing nicht threadsicher ist ;-)

Die GUI soll halt im Hintergrund aufgebaut werden, dabei soll ja gerade eben NICHT an der GUI manipuliert werden durch äusser Eingaben, wie die Maus.

Ich werde das mit der Glasspane probieren, da ich diese Idee bereits hatte, allerdings gab mir erst das Tutorial von "Gast" das entsprechende Hintergrundwissen damit richtig umzugehen.


----------



## Wildcard (1. Nov 2007)

Falscher Weg. Du kannst auch keine GUI Komponenten aus einem anderen Thread erstellen.
SWT ist da etwas direkter und wirft gleich eine Exception, Swing raucht dafür an anderen Stellen ab.
Wenn dein Programm später bugfrei sein soll, dann halt dich von allen Components fern wenn du nicht im EDT unterwegs bist.


----------



## Milbo (2. Nov 2007)

Hmm wieso nicht? Das verstehe ich nicht so ganz.
Ich hab einen Thread, der die Progressbar aktualisiert. Ich hab den AWT-Event Thread, der nix in diesen Moment nichts tuen soll. Dann habe ich halt noch den Thread, der im Hintergrund die GUI erstellt. Sind 3 Threads. Der eine steht und die anderen beiden werden vom Swingworker kontrolliert. Bevor der Thread startet Disable ich die Möglichkeiten einen neuen Thread zu starten, wobei das auch kein PRoblem ist, wenn 3 Swingworker laufen,... sieht halt nur nicht ordentlich in der Progressbar aus, weil die sich alle ein Progressbar teilen (die steht immer statisch im Hintergrund, da ich nur ein HauptFenster habe ist dieses statisch).
Mein Berechnerthread rechnet zuerst alles aus und verschiebt erst ganz zum Schluss die Daten in die GUI. Ich hatte auch keine Probleme damit. Das Problem ist halt nur, dass die Maus während der GUI erstellung im Hintergrund versucht diese bereits zu erfassen.

Hmmm was ist eigentlich der Vorteil von SWT? Ist es schneller? und what the Heck ist EDT?

Grüße Milbo


----------



## Tobias (2. Nov 2007)

EDT == Event Dispatching Thread == AWT-Event Thread == einziger Thread, der *irgendwas* mit GUI-Components machen darf. Alle anderen Threads dürfen dem EDT Aufträge erteilen, aber *niemals* direkt an der GUI rumfummeln. Dafür gibt es die SwingUtilities und SwingWorker.

mpG
Tobias


----------



## Milbo (3. Nov 2007)

Jau und ich benutze ja schliesslich nen Swingworker.... (steht ganz oben drin)

Ausserdem verstehe ich gerade die Sprachkonvention nicht.

Was meint ihr mit an der GUI rumfummeln?

Soll das bedeuten, dass die GUI nur vom AWT aufgebaut werden darf? Erscheint mir etwas seltsam, denn der Aufbau der GUI ist kein Event. nen Event wird von Listenern verarbeitet,.. oder nicht?

Zudem ist es so, dass dieser "Bug", den ich habe, weder in der laufversion des PRogrammes bemerkt wird noch sonstige Schwierigkeiten macht. Ich sehe halt nur im Eclipse, dass eine Exception fliegt, arbeiten tut das Programm so wie es soll.

Desweiteren kann man oben in der gepasteten Exception sehen, dass der "Bug" durch  at java.awt.EventDispatchThread.run(Unknown Source)  gestartet wird. Also bin ich im EDT, folglich darf er das. 
Es bleibt also alles beim alten. Gast hat die Lösung geliefert. Redispatchen!

Grüße Milbo


----------



## Wildcard (3. Nov 2007)

> Soll das bedeuten, dass die GUI nur vom AWT aufgebaut werden darf? Erscheint mir etwas seltsam, denn der Aufbau der GUI ist kein Event. nen Event wird von Listenern verarbeitet,.. oder nicht?


Genau das bedeutet es. Wenn du die Regeln ignorierst brauchst du dich nicht wundern wenn seltsame Exceptions purzeln.


----------



## Milbo (4. Nov 2007)

Sorry wildcard. Du scheinst nicht richtig gelesen zu haben. Wie ich bereits schrieb "Gast" lieferte die Lösung.

Was ich mit dem meinte, was du zitierst, war, dass Swing also nicht Multithreaded geschrieben werden kann und das ist einfach NICHT wahr. Man muß lediglich bedenken, dass Threads nicht ineinander greifen dürfen und das tue ich. 
Meine Frage war, wie sorge ich dafür, das AWT NICHT in meinen anderen Thread eingreift und das hat Gast beantwortet. Ich glaube du hast nicht richtig gelesen vermutest nen Anfängerfehler und antwortest mal drauf. Ich vermute du hast garnicht verstanden was ich tue. Das ich die Sache richtig anpacke beweist mir Gast, der ja die Lösung bereits lieferte. 
Das scheinst du irgendwie nicht akzeptieren zu wollen. Swing kann mit mehreren Threads arbeiten, was der Swingworker beweist, der nämlich aus mindestens 2 Threads besteht (oh wunder). Ich hab den Swingworker schon in java 1.5 benutzt und hatte den sourcecode selber.
Wenn du es so genau weisst, dann erklärs auch richtig und schmeiss nicht nur nen Satz hin. Ach ja dann lies bitte vorher auch genau was ich überhaupt tue, sonst redest du nämlich am Problem vorbei.
Es ist eine ganz einfache Sache. Der GUI aufbau soll durch eine Progressbar angezeigt werden um mehr gehts nicht und dies erledige ich mit dem SWINGWORKER. Was soll daran falsch sein. 

da Milbo

PS: public class ThreadDatenBlatterstellung extends SwingWorker<Void, Void> implements PropertyChangeListener{....Code....} hoffe du verstehst es jetzt. Ansonsten erklär es bitte richtig oder poste nen Link zu deinem Wissen und wirf mir nicht so seltsame Broken hin.


----------



## Guest (4. Nov 2007)

@Milbo
Solange du im SwingWorker die GUI aufbaust, nicht aber direkt in das, nennen wir es mal Hauptfenster einfügst,
wird es gut gehen. Das Hinzufügen von Komponenten zu einem Container löst schon paar Events aus, damit der
Layoutmanager was zu tun kriegt und die GUI gezeichnet werden kann. Mit dem GlassPane darüber kannst du 
"nur" verhindern, dass zusätzlich noch der User dazwischen funkt (was schon mal die halbe Miete ist).

Ich habe es in ähnlicher Form mal vor paar Jahren in einem Projekt verwendet, daher hat mich deine Frage 
daran erinnert und zu der Antwort oben bewegt.
Ich habe damals eine Art TabbedPane (eigene Views) eingesetzt, die beim Laden zunächst mal mit Daten von
einem Server initialisiert wurden. Dies dauerte u.U. paar Sekunden, da es grosse Datenmengen waren.
Zunächst war es wie folgt aufgebaut.

1) GUI-Aufbauen
2) Mit SwingWorker die Daten geladen. (SwingWorker hat damals noch etwas anders ausgesehen und war 
kein Bestandteil der API)
3) Nach dem Laden der Daten diese in die GUI gesetzt.

Problem war die Zeit zwischen 2) und 3). Manchmal sind merkwürdige Exceptions gekommen, wenn der Benutzer
angefangen hat, wie ein Wilder herumzuklicken. 
Aus dem Grund habe ich auch den Aufbau der GUI und die Befüllung der Datenmodelle in den SwingWorker
verlagert. Nach der Bearbeitung wurde die voll initialisierte View in den entsprechen Container gesetzt und
GlassPane wieder deaktiviert. Funktionierte einwandfrei.
Ich habe damals die Implementierung von SwingWorker etwas verändert, so dass GlassPane immer vor dem Ausführen
des Hintergrundthreads eingeblendet und nach dem Beenden wieder ausgeblendet wurde.
Die Progressbar war auch keine mit 0..100%, sondern eine Art Laufbalken als "Lebenszeichen". Optisch ist sowas besser
als eine tote Benutzeroberfläche. Der Benutzer hat, rein subjektiv, das Gefühl, dass die GUI schneller reagiert.

Wie auch immer. Schau dir auch das SwingSet2-Beispiel in JDK an. Insbesondere die Methoden loadDemo und addDemo 
in der Klasse SwingSet2. Dort wird sichergestellt, dass alle Events schön "hinten" angereiht werden. 
Stichwort: SwingUtilities.invokeLater

Gruß,
Dauergast


----------



## Wildcard (4. Nov 2007)

Milbo hat gesagt.:
			
		

> Swing kann mit mehreren Threads arbeiten, was der Swingworker beweist, der nämlich aus mindestens 2 Threads besteht (oh wunder). Ich hab den Swingworker schon in java 1.5 benutzt und hatte den sourcecode selber.
> Wenn du es so genau weisst, dann erklärs auch richtig und schmeiss nicht nur nen Satz hin. Ach ja dann lies bitte vorher auch genau was ich überhaupt tue, sonst redest du nämlich am Problem vorbei.
> Es ist eine ganz einfache Sache. Der GUI aufbau soll durch eine Progressbar angezeigt werden um mehr gehts nicht und dies erledige ich mit dem SWINGWORKER. Was soll daran falsch sein.


Ein Blick in die API hätte dir gezeigt das der SwingWorker eine Schnittstelle zwischen verschiedenen Threads bildet (3) und die API ganz klar bestimmt welche Methode von welchem Thread aufgerufen wird:


> There are three threads involved in the life cycle of a SwingWorker :
> 
> *
> 
> ...


Du darfst weiterhin nur in den Methoden die der EDT ausführt auf die Swing Elemente zugreifen. Wie ich dich allerdings verstehe, versuchst du im Background Thread die GUI aufzubauen und das ist eben nicht richtig. Die Glasspane mag die Folgen deines Problems beheben, aber die Ursache ist eine andere.

Wozu überhaupt das ganze? Das instanzieren der Lightweight Swing Komponenten dürfte nicht lange dauern. Wird die ProgressBar nicht vielleicht deshalt notwendig, weil das Aufbauen des Datenmodells lange dauert? Diese beiden Schritte sind klar zu trennen, dann gehe ich davon aus, das sich dein Problem gar nicht erst stellen wird.

Zum Verglech ziehe ich wieder SWT heran, da die Folgen dort unmittelbarer sind. Beide Toolkits arbeiten nach gleichem Prinzip (dem Dispatcher Thread). SWT ist allerdings konsequenter und überprüft immer ob der aufrufende Thread der Dispatch Thread ist. Falls nicht, fliegt eine Exception. Hätte Swing diese Prüfung, würde bei dir auch eine INvalidThreadAccessException fliegen


----------



## Milbo (5. Nov 2007)

Wildcard hat gesagt.:
			
		

> Wozu überhaupt das ganze? Das instanzieren der Lightweight Swing Komponenten dürfte nicht lange dauern.



Leider dauert das Aufbauen der GUI bei mir relativ lange. Es sind halt etwa 420 Variablen. Jede Variable hat ihre Beschreibung, Tooltip, Textfeld und ihre Checkbox, da bei mir Ausgabe auch gleich Eingabe ist. Das ganze wird dann noch in Panels je Formel zusammen gefasst. Tscha, das dauert halt an bissal. Das Datenmodell ist simpel, 420 Variablen als Double in einem Hashtable, das geht flott.

Meinetwegen ist es nicht so programmiert, wie es gedacht ist, aber anscheinend hat an meinen Fall auch niemand gedacht, also muss ich aussenrum programmieren. Wichtig ist mir, dass die Glasspane die der Maus was zu fressen gibt. 
Danke Wildcard für die ausführlichere Antwort, damit konnte ich jetzt wenigstens was anfangen.

Ich mache es so wie "Gast" meinte, ich lasse die GUI aufbauen und im letzten Schritt wird der Kram im HauptFenster aufgehängt. Wenn ich das umgekehrt machen würde, dann wäre es selbst mir Boon völlig klar, dass da was fliegen muss.

Yeah und nochmal vielen Dank "Gast". Deine Erläuterungen und Erklärungen und der Tipp mit der SwingSet2 demo war guat. Leider lässt Invokelater meine progressbar auch stoppen, aber interessanter Effekt ;-)

Grüße und alles was so dazugehört 
da Milbo


----------



## Wildcard (5. Nov 2007)

du hast 420 Labels, 420 Checkboxen und 420 Textfelder in einem Frame!?  :shock: 
Schonmal an eine Tabelle gedacht?


----------



## Milbo (5. Nov 2007)

Wildcard hat gesagt.:
			
		

> du hast 420 Labels, 420 Checkboxen und 420 Textfelder in einem Frame!?  :shock:
> Schonmal an eine Tabelle gedacht?


+ JPanels ;-) eigentlich sind es sogar ein paar mehr.

Jo an eine Tabelle habe ich gedacht, aber das will ich nicht, bzw ist vom Anwender später auch so nicht erwünscht. Wir haben darüber nachgedacht, aber das wäre einfach nicht das, was wir haben wollen (mein Prof, meine Auftraggeber ;-)).

Das ganze ist eine Rechenaufgabe die aus vielen Rechenschritten besteht. Der Unterschied meines Programmes zu den bereits bestehenden ist gerade das Konzept, dass jeder Rechenschritt einzeln abgehandelt werden kann, da Ing. sich normalerweise iterativ an die Lösung ranschleichen. Alles wild in eine Tabelle reinpacken gibts schon, ist sogar das teuerste Programm seiner Art (1200 euro) aber nicht sehr übersichtlich und daher nicht beliebt.

Die Aufgabe ist so ähnlich, wie wenn man ein Getriebe entwirft. Es muss schön nach VDI-Norm gerechnet werden und ist für die Großindustrie, also nen Pentium3 mit 512 MB kann man schon erwarten.

Es geht eigentlich nur darum, dass die Anwender halt merken das was passiert. Gast hat das schön erklärt.

MfG 
Milbo


----------



## Wildcard (5. Nov 2007)

Eine Tabelle muss nicht wie eine Tabelle aussehen. Swing Tabellen können dank der CellRenderer Technologie nahezu beliebige Inhalte anzeigen.
Also diese extreme Anzahl von JComponents halte ich jedenfalls für nicht optimal.


----------



## Milbo (5. Nov 2007)

Hmmm,

Ich kann dir ja mal mein Programm zuschicken, haste Windoof? Vielleicht fällt dir ja was besseres ein, weil ich gebe zu das es nicht optimal ist. Da gibt es noch so manches zu verbessern. 
Auch auf Grund des Gridbaglayouts brauchte ich manchmal ähm Hilfspanels. 
Also ich habe nen Panel, das hat für jede Zeile nen Panel und da sind die Labels, Textfelder und Checkboxen drin.

Ich bin halt nen Ingenieur der Quereingestiegen ist. Das ist von daher interessant, weil Ingenieure sich oft nicht klar sind, was sie Wirklich wollen. Sie geben dann Aufträge an Informatiker, welche tolle Programme nach den Vorgaben machen, aber viele Ings könne dann damit nicht gut umgehen. Daher bin ich halt kein studierter bzw ausgebildeter Javaprofi. Ich hatte zwar Hilfe von einem ausgebildetem Javaprogger, aber der ist auf Netzwerke spezialisiert.

Es wäre interessant für mein nächstes Programm bzw Version 2.

Haste nen nettes Tutorial dafür? Jetzt ist es wahrscheinlich zu spät das umzubauen (funzt ja). Aber ich habe vor eine ganze Reihe von Programmen der Art zu bauen, daher interessiert mich eine schlankere Lösung schon sehr.

Freundliche Grüße 
da Milbo


----------



## Wildcard (5. Nov 2007)

Ist doch Java, warum brauch ich also Windows?  ???:L 
Tutorial für was? In der FAQ haben wir ein JTable Tutorial. Dort werden auch die CellRenderer erklärt.
Anonsten bietet Sun selbst sehr umfangreiche Tutorien.


----------



## Milbo (6. Nov 2007)

Ich schau mir mal euer JTable Tutorial mal an.

Wenn ich es richtig verstanden habe, kann man sich die JTextFields und einige JPanels sparen. Zudem könnte die Datenhaltung vereinfacht werden, so wie ich das verstehe.

MfG Milbo


----------



## Milbo (28. Nov 2007)

Hab den ganzen Mist überarbeitet. 

jetzt habe ich im Schnitt etwa 40 JPanels.

Hab das ganze jetzt mit einem JTree gelöst, jetzt brauche ich keinen Swingworker mehr für den GUI-aufbau, weil es einfach so schnell genug geht.

Ich danke nochmal für den Gedankenanstoss Wildcard. Deine Gedanken und die Kritik eines gewissen Betatesters lies mich die GUI komplett überarbeiten.

MfG da Milbo


----------

