更新时摇摆组件闪烁很多

我在某处有几千行代码,我注意到当我更新它时,我的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()不是线程安全的,必须从事件线程访问。 这几乎可以肯定您的应用程序最终冻结的原因。

注意: JTextPaneJEditorPaneinheritance其setText()方法,并从JTextComponentinheritance其setCaretPosition方法,这解释了前一段中的链接未转到JTextPane JavaDoc页面。

要成为线程安全的,你真的需要至少从事件线程中调用setCaretPosition() ,你可以使用这样的代码:

 SwingUtilities.invokeAndWait(new Runnable() { public void run() { a.setText(b.toString()); a.setCaretPosition(b.length()); } } 

因为你必须从事件线程中调用setCaretPosition() ,所以你也可以从同一个地方调用setText()

您可能不需要手动设置插入位置。 查看JavaDoc for JTextComponent中的“Caret Changes”部分。

最后,您可能需要查看一系列两篇文章:

  • 更快的JTextPane文本插入(第一部分)
  • 更快的JTextPane文本插入(第二部分)

不确定这是否可行,但您可以尝试使用文本窗格的Document实例的insertString()方法。 我会尝试在文档的末尾留一个空格,并将插入符号放在该空格之后; 但是当您插入字符串时,请将其插入空格之前。 这样,插入符号位置将自动保留在文档的末尾。

我认为文本窗格可能会重新绘制两次,一次是在调用setText() ,一次是在调用setCaretPosition() ,这可能会导致闪烁。 虽然不确定(自从我使用Swing以来已经有一段时间了)。