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

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.

Diese OffscreenImages verändert man immer dann wenn es nötig ist. Also z.B. wenn sich die Größe des Buttons geändert hat, oder ein setText stattgefunden hat.

Du könntest auch mal versuchen mit setDoubleBuffered den Button an sich zum DoubleBuffering zu bewegen.

Aber immer das ganze Bild in der paint neuzuzeichnen ist sicher nicht so toll.

Was ich mich dazu aber Frage: Hast du dieses Problem auch wenn du deine Anwendung minimierst und dann wieder anzeigst. In dem Fall wird auch ein repaint durchgeführt und entsprechend sollte das auch langsam gehen sofern es dann an der paint liegt.
 
Du könntest auch mal versuchen mit setDoubleBuffered den Button an sich zum DoubleBuffering zu bewegen.

Habe ich schon versucht, keine Änderung. Ist ja auch eigentlich klar, denn im Prinzip will ich alle Buttons in einem Buffer zeichnen lassen, und nicht jeden Button in seinen eigenen, was ja diesen nacheinander-effekt auslöst.

Aber immer das ganze Bild in der paint neuzuzeichnen ist sicher nicht so toll.

Aber anders geht es nicht. Das Bild ist ja kein Icon o.Ä.. sondern stellt den Hintergrund des Buttons dar. Ändere ich den Text des Buttons, so muss auch sein Hintergrund, sprich das Bild, neu gezeichnet werden.

Was ich mich dazu aber Frage: Hast du dieses Problem auch wenn du deine Anwendung minimierst und dann wieder anzeigst. In dem Fall wird auch ein repaint durchgeführt und entsprechend sollte das auch langsam gehen sofern es dann an der paint liegt.

Habe ich gerade ausprobiert, der Effekt tritt dann nicht auf. Allerdings bezweifel ich, dass ein Paint ausgeführt wird. Es liegen ja noch ein paar Abstraktionsebenen dazwischen - das OS z.B. cached sicher auch den Fensterinhalt, der dann einfach wieder hergestellt wird oder solche Sachen. Wenn das Fenster also wiederhergestellt wird, wird nicht alles neu gezeichnet (dann tritt aber, so vermute ich, genau solch ein DoubleBuffering ein - der Fensterinhalt liegt irgendwo schon im Speicher, welche dann einfach nur noch ausgelesen wird, anstatt das Fenster neu zu zeichnen).

Ich glaube langsam, dass es einfach nicht geht. Ich kann die Buttons nicht dazu bewegen, sich zu rendern und dann auf einen Schlag zu präsentieren. Sicher geht das über Umwege, doch die sind mir im Moment jedenfalls zu umständlich.
 
Aber anders geht es nicht. Das Bild ist ja kein Icon o.Ä.. sondern stellt den Hintergrund des Buttons dar. Ändere ich den Text des Buttons, so muss auch sein Hintergrund, sprich das Bild, neu gezeichnet werden.

Natürlich geht das anders.

Du hast doch eine eigene Button-Klasse. Dann überschreib die setText Methode und ruf dann ein updateImage auf in welchem du dir deinen Button neu zeichnest.

Also so in etwa:
Java:
public class DeinButton extends JButton{

private BufferedImage bufferImage;

private void updateImage(){
 Graphics g = new Graphics(bufferdImage);
g.drawImage(image1);
g.drawImage(image2);
g.drawString(getText());
}

public void paint(Graphics g){

g.drawImage(bufferedImage);

}

}
 
Hi.

wäre es dir möglich mal einen ScreenShot zu posten,
würde mich interessieren was du da machst und ob da
Buttons überhaupt die gute Lösung sind ?

Gruß JAdix
 
Natürlich geht das anders.
Du hast doch eine eigene Button-Klasse. Dann überschreib die setText Methode und ruf dann ein updateImage auf in welchem du dir deinen Button neu zeichnest.
Also so in etwa:
...

Aber das ist doch gar nichts anderes, als wenn ich den Hintergrund in der paintComponent Methode zeichne. Wenn ich in Deinem Fall setText aufrufe, wird dadurch das updateImage aufgerufen und das Bild gezeichnet. Verwende ich bei mit setText, so wird durch paintComponent das Bild neu gezeichnet, es fällt also nur updateImage raus, aber es passiert genau dasselbe, nämlich ein Aufruf an g.drawImage.

Zugegeben, ein Unterschied ist noch, dass du den Text mit in das Bild reinrenderst, aber das macht überhaupt keinen Performance Unterschied (habe ich getestet).

wäre es dir möglich mal einen ScreenShot zu posten,
würde mich interessieren was du da machst und ob da
Buttons überhaupt die gute Lösung sind ?

In diesem Fall mache ich eine einfache Bildschirm-Tastatur (Ich habe aber noch ein paar andere GUIs, in denen Ähnliches passiert). Drücke ich die Shift-Taste, so werden alle Buchstaben auf den Buttons/Tasten groß (a -> A, b -> B, etc.). Und das geschieht in meinem Fall eben auffallend "nacheinander", was sehr unschön aussieht.

Ich glaube, wie und wann ich zeichne, das steht gar nicht mehr zur Diskussion und ich glaube auch nicht, dass es noch besser geht (ich cache alles, ich zeichne nur wenn nötig etc.). Aber g.drawImage ist und bleibt langsam, da kann man nichts dran drehen vermute ich. Deshalb suche ich eben immernoch nach so einer "im Hintergrund"-Zeichnen Möglichkeit, die es aber wohl ohne viel Arbeit nicht einfach so geschenkt gibt.

Eben gerade ist mir jedoch etwas eingefallen. Ich habe ja schon oft gesagt, dass ich g.drawImage verwende. Was ich jedoch nicht erwähnt habe ist, was für eine Signatur ich verwende - nämlich jene, mit der ich das Bild auch "on the fly" auf die Komponentengröße (Buttongröße) skaliere. Nehme ich das weg, sieht man schon einen kleinen Performanceunterschied, noch nicht perfekt, aber spürbar besser. Nun muss ich nur diese Skalierung cachen und dann könnte ich schon nen Schritt weiter sein.
 
Du verstehst einfach nicht was ich geschrieben habe. Natürlich ist das nen Unterschied ob man das ganze auf nen OffscreenImage zeichnet oder direkt auf die GUI zeichnet....
 
Hallo,

mal Butter bei die Fische !

Hab da noch ne Idee, ist aber davon abhängig ob es möglich ist deine Buttons
in ein separates Panel zu legen und dieses Panel auf den ContextPane zu packen.

Rufst du in deiner paintComponent() des Buttons noch super.paintComponent() auf ?
Wäre es evtl. möglich setText des Buttons zu überschreiben ohne super.setText()
aufzurufen ? (Das nicht zu tun hat weitreichende Folgen die über die Darstellung
hinaus gehen) Würde die Sache noch vereinfachen !

Gruß JAdix
 
Du verstehst einfach nicht was ich geschrieben habe. Natürlich ist das nen Unterschied ob man das ganze auf nen OffscreenImage zeichnet oder direkt auf die GUI zeichnet....

Dann will ich das mal versuchen aufzuschlüsseln:

Du zeichnest erst alles auf ein Offscreenimage ("bufferdImage"), danach (in der Paint Methode) per "g.drawImage" auf die GUI.

Meine Bilder liegen schon als BufferedImages vor, ich zeichne sie von dort direkt per "g.drawImage" auf die GUI. Der einzige Unterschied, den ich sehen kann ist, dass Du noch das Label ("g.drawString(getText())") mit in das Offscreenimage zeichnest. Das bringt aber keinerlei Performanceunterschied.

Ergo, du benutzt noch ein _weiteres_ Offscreenimage um dieses dann schließlich direkt auf die GUI zu zeichnen, ich benutze dieses nicht (zeichne aber natürlich auch quasi aus einem Offscreenimage heraus!).

Theoretisch läuft Deine Version sogar langsamer als meine. Denn: Du benutzt 3 Mal g.drawImage, ich benutze nur einmal g.drawImage. Wir zeichnen beide aus zuvor geladenen BufferedImages.

Falls ich dennoch etwas falsch verstanden haben sollte, würde ich mich freuen, wenn Du mir einmal den Unterschied zwischen Deiner und meiner Version klar machst.

Hab da noch ne Idee, ist aber davon abhängig ob es möglich ist deine Buttons
in ein separates Panel zu legen und dieses Panel auf den ContextPane zu packen.

Rufst du in deiner paintComponent() des Buttons noch super.paintComponent() auf ?
Wäre es evtl. möglich setText des Buttons zu überschreiben ohne super.setText()
aufzurufen ? (Das nicht zu tun hat weitreichende Folgen die über die Darstellung
hinaus gehen) Würde die Sache noch vereinfachen !

Theoretisch kann ich alle Deine Fragen mit Ja beantworten. Auch super.setText() brauche ich nicht unbedingt, da ich meine eigene Objektvariable für den Text anlegen kann (denn nur per get/setText() habe ich Zugriff auf den Text eines JButtons, da die Variable private ist).

Ach so, ein "Nein" gibt es zu "super.paintComponent()", das rufe ich in meiner painComponent() nicht auf.

Die Buttons liegen alle in einem separaten Panel.

Woraus möchtest Du hinaus?
 
Hallo,

worauf ich hinaus will ? Nun gut !

Durch das überschreiben der setText()-Methode des Buttons :

Code:
public void setText(String text) {

	mytext = text;
}

unterbindet man das für jeden Button dabei ein repaint()
zustande kommt, da die Standardimplementation des
AbstractButton diesen auslöst sobald ein neuer Text übergeben wird.

Wie du richtig angemerkt hast mit dem Feld text aus der Button-Klasse
ist dann Essig, weil privat ! Also eigenes Feld z.B. mytext anlegen.

Nun muß man sich also um das repainten selber kümmern und das
löst man nun auf dem Panel aus. In folge dessen zeichnet das
Panel alle seine Kind-Elemente in der paintChildren()-Methode.

Diese hab ich nun wie Folgt in einer eigenen von JPanel abgeleiteten
Klasse überschrieben :

Code:
protected void paintChildren(Graphics g) {
		
		Image flashbuffer = this.createImage(this.getWidth(),this.getHeight());
		Graphics g2 = flashbuffer.getGraphics();
		
                super.paintChildren(g2);

		g.drawImage(flashbuffer,0,0,this);
	}

Denn super-Aufruf mache ich mit dem Puffer-Image in Panel-Größe
das fertige Image zeichne ich dann in einem rutsch auf die Oberfläche !

Dieses Puffern passiert also nur wenn alle Kind-Elemente gezeichnet
werden müssen nicht wenn einzelne Buttons neu gezeichnet werden
müssen. (Wir haben das automatische repaint ja nur für setText ausgehebelt)

Alles klar ?

Gruß JAdix
 
Hallo,

worauf ich hinaus will ? Nun gut !
....
Alles klar ?


Auf jeden Fall :) Ich habs noch nicht selbst ausprobiert, aber genau so eine Lösung habe ich gesucht. Nicht schön, aber selten :)

Im Ernst, vielen Dank für den Beitrag - im Prinzip ist es ja kein Double Buffering, aber das Ergebnis ist fast dasselbe, denn es gibt kein "Screen refresh" zwischen den Buttons.

Sowas hätte ich jetzt gerne als Sprachelement, z.b. mit einer Anweisung von Swing, den Screen Refresh auszusetzen, z.B.:

Java:
SwingUtilities.suspendRendering();
// Zeichenoperationen
SwingUtilities.resumeRendering();

Ich denke ich werde aus Deinem Beispielcode eine Panel Klasse machen, in der man per property dieses "besondere" Rendern an- und ausschalten kann.

Falls Dir noch andere Workarounds einfallen, nur her damit :) Ich finde das Thema interessant.
 
Zurück