Perfomance Problem mit JTabbedPane - Lazy Initializing ****?

shocking

Mitglied
Hi liebe Leute,

ich hoffe Ihr könnt mir einen Denkanstoß für mein Performanceproblem geben, ich weiß nämlich langsam nicht mehr weiter.

Ich habe ein JPanel mit einem CardLayout. Dieses beherbergt zwei JPanel als "Seiten". Panel1 wird zur Suche und Anzeige der Suchergebnisse benutzt, Panel2 beinhaltet die Anzeige der detailiierten Informationen zu einem Suchergebnis.
Nach der Suche und Selektion auf Panel1 kann der Benutzer einen Button drücken, der quasi das Blättern auf die zweite Seite (also Panel2) ermöglicht. Dies wird realisiert, indem zunächst in einem Workerthread die Daten zu dem selektierten Suchergebnis aus der Datenbank gelesen, und diese dann im Anschluss über das CardLayout zur Anzeige gebracht werden.
Das Problem ist nun, dass ein Teil der Detailinformationen in einer JTabbedPane angezeigt werden soll, die dynamisch anhand der gefundenen Informationen mit Tabs gefüllt werden soll. Dh. wenn die Suchdaten 20 Abschnitte enthalten, muss die JTabbedPane dynamisch mit 20 Tabs versehen werden zur Laufzeit, genauer gesagt zwischen dem Laden der Infos und dem Anzeigen der zweiten Seite.

Mein Problem ist jetzt nicht das grundsätzliche Multithreading. Der Ladevorgang ist in einem Workerthread und funktioniert. Aber das Anzeigen der geladenen Daten dauert viel zu lang.
Dabei scheint das Problem nicht die Erzeugung der JPanel (als Container für den Inhalt der Tabs) und ihrer Komponenten zu sein, sondern vielmehr das panel.add() der einzelnen Unterpanel.
Ich habe per Microbenchmarking mal schlicht die Tabs inklusive ihrer Panel erzeugt und bin bei ca 1,3 Sekunden für das Umblättern gewesen (ja immer noch nicht schnell aber für die verarbeiteten Datenmengen annehmbar). Wenn ich nun die bereits erzeugten Panel zum Container-Panel in den einzelnen Tabs per add() hinzufüge, dauert derselbe Blättern-Vorgang 17 Sekunden...

Hat jemand eine Idee wie ich dieses Verhalten umgehen kann? Ich habe schon an eine Art lazy-Initialsierung der einzelnen Tabs gedacht, also erst alle Tabs leer hinzufügen (abgesehen vom ersten der angezeigt wird), dann umblättern und dann quasi im Hintergrund die Tabs weiter mit Komponenten füllen lassen. Aber das würde quasi bedeuten, dass ich die Panel ausserhalb des EDT erzeugen und hinzufügen müsste, was meinem Verständnis von Swing entgegen liefe...
Der eigentliche Inhalt der einzelnen Reiter wird bereits über einen PropertyChangeListener auf der JTabbedPane aktualisiert (also die Daten). Wenn ich an dieser Stelle versuche auch das Panel zur Anzeige der Daten im Tab zu initialisieren, dauert der Tabwechsel allerdings zu lang, und es gibt an dieser Stelle einen kurzen Freeze...

Es tut mir leid, dass ich nicht wirklich mit Code aufwarten kann, aber das wären leider etwas viele Klassen für Panel, Actions etc die ich dann hier posten müsste.
 

takidoso

Erfahrenes Mitglied
Hi shocking,
aus meiner Sicht sollte es nicht so arg lange dauern bis ein neuer Tab in ein JTabbedPane erstelt wird.
Du sagst außerdem, es gäbe ein freeze.
Soll Deine Anwendung noch während dr Datensuche dem Anwender die Möglichkeit bieten den Tab zu wechsln, habe ich das richig verstanden?
Vielleicht beobachtest Du, dass der Tab erst nac vervollständigen der Daten auf de neu einzufügenden Panel reingstellt wird, kann das sein?
Wenn es so ist, glaube ich, dass Dein Datensuchen als Thread vielelicht nicht da läuft wo es laufe solte.
Machst Du sowas wie invokeLater() oder invokeAndWait(). Falls es an sowas liegen sollte, ist hier eine nette Zusammenfassung was man wann benutzen sollte:
http://javarevisited.blogspot.nl/2011/09/invokeandwait-invokelater-swing-example.html

Vielleicht hilft's ja darüber sich nochmal Gedanken zu machen.

Takidoso
 
Zuletzt bearbeitet:

shocking

Mitglied
Hi,

Danke für deine Antwort.
Ich habe jetzt erstmal die Notfall-Lösung umgesetzt, dh. ich lade zunächst alle Daten in meinen Datenmodell. Dies geschieht in einem Workerthread. Im Anschluss (über SwingUtilities.invokeLater) lasse ich zunächst alle Tabs ohne Inhalt und nur mit Titel hinzufügen. Dann wird der erste Tab mit Inhalt gefüllt.
Über einen PropertyChangeListener höre ich dann auf die Selektion der Tabs und füge das Panel in den gewählten Tab, sofern dies noch nicht geschehen ist.

Nichts desto trotz dauert das erste Hinzufügen des Panels eine gute Sekunde. Da der Edt dafür ja zeichnen muss, friert die Anwendung diese Sekunde über leicht ein.
Ich könnte mir vorstellen, dass der Inhalt des Panels zu aufwendig ist. Er besteht aus einen Container-Panel, welches eine ScrollPane beinhaltet. In dieser ScrollPane wird wiederum ein Container-Panel platziert, welches mehrere kleinere Panel beinhaltet. Ein Teil dieser Panel beinhaltet auch swingx CollapsiblePanes, die ein- bzw. ausgeklappt werden. Dadurch muss schon ein wenig gerechnet werden für die PreferredSize in der ScrollPane könnte ich mir vorstellen.
Da diese Dinge aber gefordert sind, weiß ich halt nicht wie ich das verbessern kann.
Ich verwende such ausgiebig das JGoodies Formlayout. Könnte das auch Timingprobleme geben?
 

takidoso

Erfahrenes Mitglied
Leider habe ich bisher noch nie mit z.B. CollapsiblePanes gearbeitet. Ic habe meist mit GidBagLayout, JScrollPane und JSplitPane gearbeitet.
Ich finde eine Sekunde ist doch noch für das erstemal ganz in Ordnung, oder? denn wenn Du erstmal so ein Panel erzeugt hast und dann wieder hin und zurück wechselst ist es doch sicher schneller.
Ma eine blöde Frage was macht eigentlic das Collabible Panel, kann man seine Funktionalität vielleicht auch mit einfacheren Panels darstellen?
 

shocking

Mitglied
Ja ab dem 2. mal blättern ist das ganze schnell und ohne Verzögerung. Es ärgert mich nur, dass so wenige grafische Elemente so "teuer" in der Performance und scheinbar auch im (kurzzeitigen) Speicherverbrauch sind. Schließlich versuche ich an der Stelle nicht gerade eine 3D-Animation zu zeichnen, sondern lediglich ein paar JPanel mit ein paar Elementen wie Textfeldern, Labels und ComboBoxes etc...

Zu deiner Frage:
Eine CollapsiblePane ist quasi eine Pane, welche sich animiert ein- und ausklappen lässt. Man kann so ziemlich jeglichen Inhalt in so einer Pane platzieren (in meinem Fall halt ein JPanel mit Inhalt), und diesen dann per z.B. Buttonklick animiert anzeigen oder ausblenden lassen. Dies ließe sich sicher auch über einen Timer-Task und ein normales JPanel lösen. Aber warum das Rad neu erfinden, wenn es schon ein rundes gibt?
 

takidoso

Erfahrenes Mitglied
Ahh nun weiß ich was das ist. Hatte gegoogelt und fand heraus dass es offenbar ein Third-Party-Bibliothek dafür zu verwenden ist.
Stimmt, das Rad würde ich auch nicht neu erfinden wollen. Wen ma Show haben möchte wie animation nur weil etwas sich verabschiedet... Ich selbst sage mir da eher weniger ist mehr. Aber wenn der Kunde das unbedingt haben möchte ... tja :)