頻繁に更新すると Swing コンポーネントがちらつく
-
21-08-2019 - |
質問
どこかに数千行のコードがあり、更新しすぎると JTextPane がちらつくことに気づきました。ここに簡略版を書きました。
import java.awt.*;
import javax.swing.*;
public class Test
{
static JFrame f;
static JTextPane a;
static final String NL = "\n";
public static void main(String... args)
{
EventQueue.invokeLater(new Runnable(){
public void run()
{
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.setSize(400, 300);
f.setLocationRelativeTo(null);
a = new JTextPane();
f.add(new JScrollPane(a));
new Thread(new Runnable(){
public void run()
{
int i = 0;
StringBuffer b = new StringBuffer();
while(true)
{
b.append(++i+NL);
a.setText(b.toString());
a.setCaretPosition(b.length());
try{Thread.sleep(10);}catch(Exception e){}
}
}
}).start();
}
});
}
}
これはターミナル (cmd) スタイルの GUI コンポーネント用です。
ここでできる限りの最適化をすべて行ったと思います。 \n
最終変数として使用するため、何百回も構築されません。それでも、ちらつきは目立ち、許容できないものです。数分後、コンポーネントは完全にフリーズします。コンポーネントを迅速に更新する必要があり、更新時にはペインを一番下までスクロールする必要があります。
私は独自のバージョンの JTextPane を最初から作成することを考えてきましたが、もっと簡単な解決策があるかどうかを確認したいと思います。
解決
エラーの一部は、イベント スレッドの外部から Swing コンポーネントにアクセスしていることです。はい、 setText() はスレッドセーフですが、Swing メソッドは明示的に宣言されない限りスレッドセーフではありません。したがって、 setCaretPosition() はスレッドセーフではないため、イベント スレッドからアクセスする必要があります。アプリケーションが最終的にフリーズするのは、ほぼ確実にこれが原因です。
注記: JTextPane
そのものを継承する setText()
からのメソッド JEditorPane
そしてその setCaretPosition
からのメソッド JTextComponent
, これは、前の段落のリンクが次のページに移動しないことを説明しています。 JTextPane
JavaDocページ。
スレッドセーフにするためには、少なくとも次の呼び出しを行う必要があります。 setCaretPosition()
イベント スレッド内から、次のようなコードで実行できます。
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
a.setText(b.toString());
a.setCaretPosition(b.length());
}
}
そして、電話する必要があるので、 setCaretPosition()
イベントスレッド内から、を呼び出すこともできます。 setText()
同じ場所から。
キャレットの位置を手動で設定する必要がない場合もあります。JavaDoc の「Caret Changes」セクションを確認してください。 JTextコンポーネント.
最後に、次の 2 つの記事シリーズをご覧ください。
他のヒント
これが機能するかどうかわからないが、あなたは、テキスト・ペインのinsertString()
インスタンスのDocument
メソッドを使用して試みることができます。私は、文書の最後に単一のスペースを有し、かつ、そのスペースの後に配置キャレットを維持しようとするだろう。あなたは、文字列を挿入するときには、スペースの前に挿入します。こうすることで、キャレット位置が自動的に文書の最後に残るます。
私はあなたがsetText()
を呼び出すときに一度setCaretPosition()
を呼び出し、一度際、テキスト・ペインが二回再描画を取得するかもしれないと考えている、それがちらつきに貢献している可能性があります。わからない、しかし(私はスイングで働いていたので、それがしばらくしている)。