[英]Swing component flickering when updated a lot
我在某處有幾千行代碼,我注意到當我更新太多 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
從JEditorPane
繼承其setText()
方法,從JTextComponent
繼承其setCaretPosition
方法,這解釋了上一段中的鏈接不會轉到JTextPane
JavaDoc 頁面。
為了線程安全,您至少需要從事件線程中調用setCaretPosition()
,您可以使用如下代碼執行此操作:
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
a.setText(b.toString());
a.setCaretPosition(b.length());
}
}
而且由於您必須從事件線程中調用setCaretPosition()
,因此您也可以從同一位置調用setText()
。
您可能不需要手動設置插入符號 position。 查看JTextComponent的 JavaDoc 中的“插入符號更改”部分。
最后,您可能想查看一系列兩篇文章:
不確定這是否可行,但您可以嘗試使用文本窗格的Document
實例的insertString()
方法。 我會嘗試在文檔末尾有一個空格,並將插入符號放在該空格之后; 但是當你插入一個字符串時,將它插入到空格之前。 這樣插入符號 position 將自動保留在文檔的末尾。
我認為文本窗格可能會被重繪兩次,一次是在您調用setText()
時,一次是在您調用setCaretPosition()
時,這可能會導致閃爍。 不過不確定(自從我使用 Swing 以來已經有一段時間了)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.