Text vieler Buttons ändern, Änderung sofort darstellen (nicht einer nach dem anderen)

DarthShader

Erfahrenes Mitglied
Hallo,

ich habe ein JFrame, in dessen ContentPane sich recht viele JButtons befinden (mehr als 50).

Nun muss ich während des Programmablaufes die Beschriftung (Text Eigenschaft) aller Buttons ändern. Dies mache ich bisher in einer normalen Schleife, etwa so:

Java:
for ( JButton button : buttonList ) {
	button.setText( "foo" );
}

(Der Code läuft im event dispatching thread von Swing, weil er von innerhalb eines Listener ausgeführt wird).

Das funktioniert natürlich, ist aber sehr "unschön", denn nachdem eine Beschriftung eines Buttons geändert wurde, wird er oder der ganze Frame anscheinend sofort neu gezeichnet. Das führt dazu, dass nicht alle Buttons gleichzeitig die Beschriftung erhalten, sondern man sieht deutlich "einer nach dem anderen".

Im Prinzip stelle ich mir so eine Art flag vor, dass ich setzen kann, damit keine Screen-Updates gemacht werden, und erst nachdem die Schleife durchgelaufen ist wird alles auf einen Streich neu gezeichnet. Oder eine Art DoubleBuffering, im Hintergrund wird es neu gezeichnet und dann auf einmal sichtbar gemacht.

Deshalb meine Frage, wie könnte ich das lösen?


Vielen Dank für Eure Hilfe!
 
Hi,

ich hab da ne Idee aber ich konnte sie nicht Testen !

Habe das mal nachgebaut Frame mit BorderLayout darin Panel mit GridLayout
darin 60 Buttons.
Einen weiteren Button mit dem ich einen ActionListener starte der mir alle
60 Buttons umdeklariert.

Fazit selbst nach dem ich den Event-Thread mit Thread.sleep(250) schööööön
runtergebremst habe, konnte ich dein beschriebenes nacheinander aktualisieren
nicht erkennen ?

Gib nochmal ein paar Infos zu deiner GUI ! Struktur, LayoutManager etc.
evtl. noch den Code des ActionListeners !

Gruß JAdix
 
Hallo,

danke für Deine Antwort. Ich denke ich hätte noch ein wenig mehr schreiben sollen. Zugegeben, es handelt sich um eine eigene Button Klasse, die direkt von JButton erbt. Diese Klasse zeichnet sich selbst, was sicher nicht sehr schnell geht (es werden Bilder gezeichnet, um die Buttons ansprechend aussehen zu lassen).

Allerdings hat das ja nur indirekt mit meiner Frage zu tun. Mir ist klar, dass so ein Zeichnen solcher Buttons nicht sehr fix ist (mit JButtons direkt habe ich auch kein Problem), aber ich möchte eben nicht, dass alles nacheinander angezeigt wird (sprich, pro button ein screen update), sondern gleichzeitig.
 
Wie groß sind denn deine Buttons dass das Zeichnen so lange dauert? Arbeitest du schon mit einem gepufferten Bild was dann nur noch fertig gezeichnet werden muss?

Ansonsten würde mir nur einfallen dass auf Threads zu verteilen.
 
Wie groß sind denn deine Buttons dass das Zeichnen so lange dauert? Arbeitest du schon mit einem gepufferten Bild was dann nur noch fertig gezeichnet werden muss?

Ja, das sind alles zuvor geladene Bilder aus einem cache. Es handelt sich um einfache BufferedImage Bilder - zumal es sich eigentlich nur um 9 Bilder handelt (ein Button hat 4 Kanten, 4 Ecken und ein mittleres Bild). Die Buttons sind alle ca. 35x35 Pixel groß.

Ich muss auch zugeben, dass ich sehr empfindlich bin, was das angeht. Sicher gibt es Leute, die da drauf gucken und sagen, dass es überhaupt nicht schlimm sei. Aber Performance ist mir wichtig, und nur weil ich den Text von den Buttons änder sieht man deutlich, wie alles nacheinander aktualisiert wird.

Kann man nicht dieses Zeichnen irgendwie im Hintergrund machen und dann alles auf einmal Darstellen? Das typische Double Buffering eben? Ich weiß, dass man z.B. für einen Button DB einstellen kann, aber ich will ja, dass das Zeichnen aller Buttons in einem Hintergrundbuffer stattfindet, nicht nur für einen alleine.

Ansonsten würde mir nur einfallen dass auf Threads zu verteilen.

Hm, also Du meinst, wenn ich 50 Buttons habe, erstelle ich nen Thread Pool mit 50 Threads und sage in jedem, dass der Buttontext eines Buttons geändert werden soll? Ich kann mir nicht vorstellen, dass das funktioniert, denn müssen solche Operationen nicht alle in demselben Event Dispatching Thread von Swing ausgeführt werden? Müsste ich mal ausprobieren... obwohl mir das ein wenig oversized vorkommt, da auf einmal so eine Thread Armada aufzumachen :)
 
Also malst du jedes mal diese 9 Bilder einzeln auf den Button?

Ich würde ja das schon in ein Image schreiben was zum Button gehört und bei setText auch schon entsprechend das Image verändern und beim paint nur noch das fertige Bild zeichnen.
 
Hallo,

ich sag mal so, zeja's Idee ist gut, nur wann zeichnet man dann diese Images ?
Tut man dieses wieder in der paint-Methode bringt das nichts.

Welches paint hast du eigentlich überschrieben ?
paint(g) oder paintComponent(g) ?

Bist du dir gaaanz sicher das direkt der Event-Thread deine Buttons ändert ?

Hab das mal Nachgebaut (die Zweite) :

Eigener Button, malt nach dem super-Aufruf noch 8 Bildchen (16*16 Pixel )
auf die Button-Fläche, sonst wie oben also alles mal 60 usw.

Nur wenn ich im ActionListener einen neuen Thread erzeuge und starte
der das Textändern ausführt, bekomme ich diesen Nacheinander-Effekt.

Also entweder du postest mal ein bischen Code oder wir Rätseln hier noch
Wochen rum !

Gruß JAdix
 
Also malst du jedes mal diese 9 Bilder einzeln auf den Button?

Ich würde ja das schon in ein Image schreiben was zum Button gehört und bei setText auch schon entsprechend das Image verändern und beim paint nur noch das fertige Bild zeichnen.

Ich habe das ausprobiert und es bringt keine Performance Vorteile. Der Flaschenhals ist wirklich die g.paintIamge(...) Methode, die das Bild bei mir zeichnet (das Bild wird auch skaliert). Kommentiere ich es aus, geht es recht fix.

ich sag mal so, zeja's Idee ist gut, nur wann zeichnet man dann diese Images ?
Tut man dieses wieder in der paint-Methode bringt das nichts.

Welches paint hast du eigentlich überschrieben ?
paint(g) oder paintComponent(g) ?

Ich habe die paintComponent Methode überschrieben, in der zeichne ich das Bild (bzw. die 9 Bilder, die einen Button ausmachen), sowie den Text des Buttons.


Bist du dir gaaanz sicher das direkt der Event-Thread deine Buttons ändert ?

Also ich habe einen Button in dem Fenster, auf den habe ich einen ActionListener gelegt. In der actionPerformed Methode dieses Listeners steht der Code, den ich oben schon gepostet habe, also die kleine Schleife, die den Text verändert. Dies wird doch dann im Event-Thread ausgeführt, oder?


Hab das mal Nachgebaut (die Zweite) :

Eigener Button, malt nach dem super-Aufruf noch 8 Bildchen (16*16 Pixel )
auf die Button-Fläche, sonst wie oben also alles mal 60 usw.

Nur wenn ich im ActionListener einen neuen Thread erzeuge und starte
der das Textändern ausführt, bekomme ich diesen Nacheinander-Effekt.

Hm sehr merkwürdig. Und wenn Du den Thread in paintComponent ein wenig künstlich verlangsamst, sodass Du quasi meine langsame g.paintImage Methode simulierst (ohne jetzt neue Threads zu erzeugen), dann kommt dieser Nacheinander-Effekt nicht?


Also entweder du postest mal ein bischen Code oder wir Rätseln hier noch
Wochen rum !

Das ist nicht so einfach, der Code ist sehr umfangreich und ich bräuchte sicher einige Zeit, bis ich eine abgespeckte Version hier posten kann. Wenn wir aber wirklich nicht weiter kommen, werde ich das auf jeden Fall noch tun.
 
Man muss beachten das Computer (vor allem Quellcodes) imperativ arbeiten. Solltest du es schaffen für jeden Button einen eigenen Thread zu erzeugen und diese so synchron laufen zu lassen, könnte es eventuell funktionieren. *

Oder du wartest bis es Chipsätze mit genügend Kerne für dein Programm gib. Dann könntest du nämlich jeden Kern einen Button(oder vielleicht auch zwei ;)) zuweisen.


* selbst wenn zwei Thrads laufen gaukelt uns das System dies nur vor! Es wechselt in Wirklichkeit schnell(sehr schnell) hin und her. Ein PC ist nicht Multitasking fähig!**

** so wie wir Menschen! (Frauen eingeschlossen)
 
Hallo Stigma,

Deine Ausführungen sind mir durchaus bewusst :) Mir ist klar, dass, wenn man die Abstraktionslevel immer weiter runter geht, irgendwann alles sequenziell läuft.

Das hat aber nicht wirklich was mit dieser Geschichte zu tun. Natürlich werden die Buttons nacheinander geändert, aber die Anzeige sollte so schnell sein, dass es so aussieht, als würden sie alle gleichzeitig geändert (Was mit einem JButton ja durchaus geht).

Ich würde nur irgendwie gerne den Flaschenhals "g.drawImage" wegbekommen, eben z.B. mit einem Hintergrundbuffer, in den gezeichnet wird, und das Ergebnis wird dann sofort präsentiert. So, wie "flackerfreie" Computergrafik schon seit Urzeiten funktioniert :)
 

Neue Beiträge

Zurück