Swing组件更新频繁时闪烁
我在某处有几千行代码,我注意到当我更新太多时,我的 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 版本,但我想看看你们是否有更简单的解决方案。
I've got a couple thousand lines of code somewhere and I've noticed that my JTextPane flickers when I update it too much.. I wrote a simplified version here:
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();
}
});
}
}
This is for a terminal (cmd) style GUI component--
I think I've made all the optimizations I could here, including having \n
as a final variable so it won't be constructed hundreds of times. Still, the flickering is noticeable and unacceptable. After a few minutes, the component freezes completely. I must update the component very quickly, and the pane must be scrolled to the bottom when updated.
I've been thinking about making my own version of JTextPane from scratch, but I'd like to see if you guys have an easier solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的部分错误是您正在从事件线程外部访问 Swing 组件! 是的, setText( ) 是线程安全的,但 Swing 方法不是线程安全的,除非明确声明它们。 因此, setCaretPosition()< /a> 不是线程安全的,必须从事件线程访问。 这几乎肯定是您的应用程序最终冻结的原因。
注意:
JTextPane
从JEditorPane
继承其setText()
方法,并从JTextComponent
继承其setCaretPosition
方法code>,它解释了上一段中的链接不会转到JTextPane
JavaDoc 页面。为了实现线程安全,您确实至少需要从事件线程内调用 setCaretPosition() ,您可以使用如下代码来执行此操作:
并且因为您必须调用 setCaretPosition() 在事件线程内,您也可以从同一位置调用
setText()
。您可能不需要手动设置插入符位置。 查看 JavaDoc 中的“插入符更改”部分,了解 JTextComponent。
最后,您可能想查看由两篇文章组成的系列:
Part of your error is that you are accessing a Swing component from outside the event thread! Yes, setText() is thread-safe, but Swing methods are not Thread-safe unless they are explicitly declared as such. Thus, setCaretPosition() is not Thread-safe and must be accessed from the event thread. This is almost certainly why your application eventually freezes.
NOTE:
JTextPane
inherits itssetText()
method fromJEditorPane
and itssetCaretPosition
method fromJTextComponent
, which explains the links in the previous paragraph not going to theJTextPane
JavaDoc page.To be Thread-safe, you really need to at least call
setCaretPosition()
from within the event thread, which you can do with code like this:And since you have to call
setCaretPosition()
from within the event thread, you might as well also callsetText()
from the same place.It's possible that you may not need to manually set the caret position. Check out the section "Caret Changes" in the JavaDoc for JTextComponent.
Finally, you may want to check out a series of two articles:
不确定这是否有效,但您可以尝试使用文本窗格的
Document
实例的insertString()
方法。 我会尝试在文档末尾添加一个空格,并将插入符号保留在该空格之后; 但是当您插入字符串时,请在空格之前插入它。 这样插入符号位置将自动保留在文档的末尾。我认为文本窗格可能会重绘两次,一次当您调用
setText()
时,一次当您调用setCaretPosition()
时,这可能会导致闪烁。 但不确定(自从我使用 Swing 以来已经有一段时间了)。Not sure if this will work, but you could try using the
insertString()
method of the text pane'sDocument
instance. I would try having a single space at the end of the document and keeping the caret positioned after that space; but when you insert a string, insert it before the space. That way the caret position will remain at the end of the document automatically.I'm thinking that the text pane might be getting redrawn twice, once when you call
setText()
and once when you callsetCaretPosition()
, and that might be contributing to the flickering. Not sure, though (it's been a while since I worked with Swing).