Java Swing组件在大量更新时闪烁
我在某个地方有几千行代码,我注意到我的JTextPane在更新太多时会闪烁。。我在这里写了一个简化版本:Java Swing组件在大量更新时闪烁,java,multithreading,swing,flicker,jtextpane,Java,Multithreading,Swing,Flicker,Jtextpane,我在某个地方有几千行代码,我注意到我的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) {
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版本,但我想看看你们是否有更简单的解决方案。不确定这是否可行,但您可以尝试使用文本窗格的
文档实例的insertString()
方法。我会尝试在文档末尾留一个空格,并将插入符号放在该空格之后;但插入字符串时,请将其插入空格之前。这样,插入符号位置将自动保留在文档末尾
我认为文本窗格可能会被重绘两次,一次是在调用setText()
时,一次是在调用setCaretPosition()
时,这可能是导致闪烁的原因。但不确定(我已经有一段时间没有使用Swing了)。部分错误在于您正在从事件线程外部访问Swing组件!是的,它是线程安全的,但是Swing方法不是线程安全的,除非它们被显式声明为线程安全。因此,它不是线程安全的,必须从事件线程访问。这几乎肯定就是应用程序最终冻结的原因
注意:JTextPane
继承了JEditorPane
中的setText()
方法和JTextComponent
中的setCaretPosition
方法,这解释了上一段中没有指向JavaDoc页面的链接
为了线程安全,您确实需要至少从事件线程中调用setCaretPosition()
,您可以使用如下代码:
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
a.setText(b.toString());
a.setCaretPosition(b.length());
}
}
由于必须从事件线程内调用setCaretPosition()
,因此也可以从同一位置调用setext()
您可能不需要手动设置插入符号位置。请查看JavaDoc中的“插入符号更改”部分,了解更多信息
最后,您可能想查看由两篇文章组成的系列文章:
为什么奇怪地强调“专家”一词?你认为侮辱我们会得到更好的答案吗?对不起,无意冒犯。编辑。我真的不能把所有这些都放在EDT中,因为sleep()会把它阻塞得太厉害,以至于组件会完全冻结。不是sleep!但是setCaretPosition必须在EDT中。否则你会经历偶尔的(或不是那么偶然的)挂起。回答得好;只需要)代码>添加到代码末尾。