# JTextPane - insertText beschleunigen



## 0xdeadbeef (19. Apr 2005)

Habe ein kleines Problem mit der Geschwindigkeit der Methode "insertText" von JTextPane.

Ich benutze ein JTextPane als Ausgabekonsole eines skriptfähigen Taschenrechners (http://home.arcor.de/0xdeadbeef/).
JTextPane nehme ich, um farbigen Text auszugeben. Außerdem brauche ich die Funktionalität zum Markieren und Kopieren von Text. Davon abgesehen ist JTextPane und das dahinterliegende Dokument viel zu aufgeblasen und langsam für meinen Anwendungszweck.

Den Text füge ich vom Parserthread aus in die JTextPane in der Oberflächenklasse ein und benutze dazu einen Listener (addListener usw.). Das erzeugt auch eine nicht unwesentliche Menge an Event-Objekten, aber das schien mir die sauberste Lösung zu sein.

Wenn ich mit dem Skriptparser des Taschenrechners in einer Schleife Text ausgebe, verbraucht insertText > 80% der Rechenzeit. Wolhbemerkt: das gesamte Parsen und Interpretieren meiner eigenen Skriptsprache - zumal nicht sonderlich optimiert - fällt überhaupt nicht ins Gewicht gegenüber der Ausgabe per JTextPane.

Trotz katastrophaler Performance könnte ich ja trotzdem noch damit leben, aber es kommt noch schlimmer:
Um so länger der Text im JTextPane wird, um so länger dauert das Einfügen. Dadurch kommt es bei gleichmäßig flotten Einfügen zu einer exponentiellen Verlangsamung der Textausgabe, bis sie schließlich ganz einfriert. Nach einigen tausend Texteinfügungen (jeweils ein paar Zeichen) friert dann offensichtlich das ganze Swing-Rendering ein, obwohl ich ja in einem eigenen Thread rechne und auch von dort aus den Text einfüge. Ich vermute, daß die Request zum Einfügen/Neuzeichnen schneller eintreffen, als sie abgearbeitet werden können, was früher oder später zum Exitus führt.

Daß das überhaupt passiert, muß bedeuten, daß nach dem Aufruf von insertText das Einfügen des Textes noch nicht komplett abgeschlossen ist. Ich vermute mal, daß das Update der Darstellung der JTextPane asynchron in irgendeinem Swing-Thread erfolgt. Und genau das bricht mir den Hals.

Ich habe jetzt wirklich eine Menge probiert (hauptsächlich Buffer-Strategien), aber irgendwie hatte keine Methode so richtig Erfolg. Und zwar wohl deshalb, weil damit zwar die Ausgabe schneller wird, das grundsätzliche Problem (Ausgaben treffen schneller ein als sie abgearbeitet werden) aber nicht gelöst wird.
Die einzige Methode, die Abhilfe schafft, ist es nach der Erzeugung des Listener-Events eine kurze Pause per Sleep einzufügen. Das scheint dem (postulierten) Swing-Thread Zeit zu geben, seine Ausgabe zu beenden, so daß es nicht zu der beschriebenen exponentiellen Anhäufung unausgeführter Insert-Requests kommen kann. Natürlich ist das extrem unsauber und häßlich. Außerdem verlangsamt sich dadurch die Textausgabe nochmals.

Was ich bräuchte, wäre eine Möglichkeit, meinen Parserthread so lange schlafen zu legen, bis der Swing-Thread mit dem Update des JTextPanes fertig ist. Leider habe ich eine solche Möglichkeit bislang nicht gefunden.
Irgendwelche Vorschläge???

Davon abgesehen wäre ich ganz allgemein an einem perfomanteren Ersatz für JTextPane interessiert, wobei ich mit einem extrem simplen Dokumentenmodell zufrieden wäre, solaneg man nur Text einfärben kann. Aber obwohl ich wirklich lange und intensiv rumgesurft bin, habe ich keinen geeigneten Ersatz gefunden. Kann es wirklich sein, daß es keine freie und effizient implementierte Klasse zur Erzeugung einer Konsolenausgabe mit farbigem Text gibt?
Ehrlich gesagt steht mir nicht wirklich de Sinn danach, mir sowas selber zu schreiben. Die Ausgabe wäre ja noch recht einfach, aber das ganze Markier-/Kopierzeugs muß ich nicht unbedingt selber zusammenzimmern...

Mich würde auch interessieren, ob es während des Einfärbens des Textes per setCharacterAttributes (zusätzliches Syntax-Highlighting) eine Möglichkeit gibt, das Neuzeichnen der JTextPane zu unterbinden, um die Geschwindigkeit zu erhöhen. Ich habe mit Doublebuffering mittels zweier Dokumente experimentiert (ins eine Schreiben, während das andere dargestellt wird), aber beim Umschalten kommt es zu unschönem Flackern.

Wäre für zielführende Hinweise dankbar.


----------



## Wildcard (19. Apr 2005)

Hab das Problem schonmal mit Hobbit_Im_Blutrausch besprochen.
http://www.java-forum.org/de/viewtopic.php?t=16120
scheinbar ist das lineWrapping der Killer in TextPane/TextArea...
Versuch mal es testweise auszuschalten und vergleich die Antwortzeiten


----------



## 0xdeadbeef (19. Apr 2005)

Leider brauche ich das Wrapping, weil ich ja u.U. sehr große Zahlen ausgeben muß. Ich kann auch nicht so ganz glauben, daß das Ausschalten des Wrappings soviel bringt.

Und nochmal: Geschwindigkeit ist zunächst mal sekundär (obwohl sich da auch was tun sollte). Was mir IMHO den Hals bricht, ist die Nebenläufigkeit der Swing-Neuzeichnerei. Primär brauche ich also eine Möglichkeit, um auf das Ende des Neuzeichnens der JTextPane zu warten.


----------



## Wildcard (19. Apr 2005)

Oxdeadbeef hat gesagt.:
			
		

> Leider brauche ich das Wrapping, weil ich ja u.U. sehr große Zahlen ausgeben muß. Ich kann auch nicht so ganz glauben, daß das Ausschalten des Wrappings soviel bringt.


Ich kann jetzt nicht genau sagen woran es bei dir liegt, aber als ich mal einen Test gemacht hab mit 20000 Zeichen (oder so)
und LineWrapping hab ich zu meinem Entsetzen feststellen müssen das selbst nach dem setzen des Textes(was schon sehr lang dauert) die Anwendung nicht mehr bedienbar ist. Also ein ähnlicher Effekt wie du ihn festgestellt hast.
Ich würd's testhalber einfach versuchen, dann weißt du zumindest woran's liegt(oder eben nicht  :wink: ).


			
				Ocdeadbeef hat gesagt.:
			
		

> Und nochmal: Geschwindigkeit ist zunöchst mal sekundär (obwohl sich da auch was tun sollte). Was mir IMHO den Hals bricht, ist die Nebenläufigkeit der Swing-Neuzeichnerei. Primär brauche ich also eine Möglichkeit, um auf das Ende des Neuzeichnens der JTextPane zu warten.


Fällt mir jetzt spontan auch nichts ein, weil ich nicht keine Ahnung hab wie Swing das intern regelt...


----------



## 0xdeadbeef (20. Apr 2005)

Ich habe zumindest für mein Hauptproblem (die Synchronisation) eine Lösung gefunden:
Nach dem insertString() kann man auf folgende Weise die Synchronisation mit dem Swing-Thread erzwingen:


```
// synchronize with AWT thread
try {
    SwingUtilities.invokeAndWait(new Runnable() {public void run() {}});
} catch (Exception e) {
    e.printStackTrace();
}
```

Damit kommt es zumindest nicht mehr zum Einfrieren der Oberfläche, wenn man zu schnell zu viel Text einfügt.
Schneller wird das Rendering natürlich nicht - aber immerhin besser als die Sleep-Variante.

BTW: eine HTML-Seite mit einem JEditorPane laden und darstellen ist ja auch *erschreckend* langsam.
Da kann man die Leute verstehen, die Java generell für lahm halten...


----------

