以下是一篇文章:
有人插队了!有时会出现一些swing事件在事件队列中按不正确的顺序处理(没有什么会像某个人进入队列时那样让我的血液沸腾),从而导致奇怪的行为。这最好用一个小的代码片段来说明。阅读下面的片段,仔细考虑一下您所设想的事件将发生的顺序。
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
repaint();
doSomething();
}
});大多数开发人员都会对重新绘制()方法的图像进行映像,这将导致在doSomething()方法调用之前进行绘制操作。然而,实际情况并非如此,对create ()的调用将创建一个新的case事件,该事件将被添加到事件队列的末尾。只有在当前操作事件完成后,才会处理(分派)此新画图事件。这意味着doSomething()方法将在分派队列上的新画图事件之前执行。
这里的关键点是,对create ()的调用将创建一个新的that事件,该事件将被添加到end事件队列中,而不是立即处理。这意味着没有任何事件会跳出队列(我的血液可以保持在正确的温度)。
(来源)
我的问题是,如何在repaint();之前强制Swing完成doSomething();
另外,如果在repaint()中调用了doSomething();方法,那么只有在doSomething();完成后才会执行。有什么方法可以暂停doSomething();中间执行,然后提交reapaint();,完成它,然后继续doSomething();
到目前为止,我找到的唯一解决方案是这(链接),但实际上并不实用.
发布于 2013-08-05 15:56:29
好吧,你和这篇文章的作者都漏掉了这一点。“重新绘制”方法调用简单地通知重绘管理器:
因此,在什么时候进行重绘并不重要,因为如果您为同一个组件一个接一个地调用大量重绘,您甚至可能不会注意到它。这也是为什么这样的后续调用可能会被合并。请检查此示例:
private static int repaintCount = 0;
public static void main ( String[] args )
{
final JComponent component = new JComponent ()
{
protected void paintComponent ( Graphics g )
{
try
{
// Simulate heavy painting method (10 milliseconds is more than enough)
Thread.sleep ( 10 );
}
catch ( InterruptedException e )
{
e.printStackTrace ();
}
g.setColor ( Color.BLACK );
g.drawLine ( 0, 0, getWidth (), getHeight () );
repaintCount++;
System.out.println ( repaintCount );
}
};
component.setPreferredSize ( new Dimension ( 200, 200 ) );
JFrame frame = new JFrame ();
frame.add ( component );
frame.pack ();
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
new Thread ( new Runnable ()
{
public void run ()
{
try
{
Thread.sleep ( 1000 );
}
catch ( InterruptedException e )
{
e.printStackTrace ();
}
System.out.println ( "Starting repaint calls" );
for ( int i = 0; i < 100000; i++ )
{
component.repaint ();
}
System.out.println ( "Finishing repaint calls" );
}
} ).start ();
}这是您将看到的大致输出(可能会根据计算机速度、Java版本和许多其他条件而有所不同):
1
Starting repaint calls
2
3
4
5
6
Finishing repaint calls
7
8"1“-框架显示时的初始重绘。
“2,3,4.”
“但是我叫了100000重漆,不是7!”--你会说。是的,重绘管理器合并了那些相似的,同时在重绘队列中。这是为了优化重绘和加速UI的整体。
顺便说一句,您不需要从EDT调用重新绘制,因为它不执行任何真正的绘制,只需要为将来的组件更新排队。它已经是线程安全的方法了。
总结--在执行其他操作之前,不应该有真正需要重新绘制组件的情况(这也会导致组件重新绘制)。只需在需要重新绘制组件时调用重绘(在可能的情况下使用指定的矩形)-重新绘制管理器将完成其余的操作。这很好,除非你把一些计算放在油漆方法中,这是完全错误的,可能会导致很多问题。
发布于 2013-08-05 15:55:46
queue ()向事件调度线程(EDT)队列的末尾添加一个新的油漆请求。因此,在repaint() ()完成后,在doSomething()中多次调用doSomething才会重新绘制。(我假设doSomething()总是从EDT调用的。您的代码示例从doSomething()内部调用actionPerformed(它总是从EDT调用)。
reason ()请求排队的原因是减少了绘制组件的次数。排队重新绘制()请求允许几种方法将不同的组件标记为脏的,这样它们都可以在一个昂贵的same ()操作中同时重新绘制。
如果您真的想立即强制重绘,可以使用像paintImmediately(Rectangle r)和paintImmediately(int x, int y,int w,int h)这样的方法,但是您必须知道要重新绘制的维度。
如果您对Swing组件正在使用的当前图形有一个引用,那么您也可以自己调用paint(Graphics g)。(您还可以使用此技术从Image对象创建自己的图形对象,如果您想要截图并将其写入图片文件)。
https://stackoverflow.com/questions/18062126
复制相似问题