Kar*_*120 3 java swing multithreading event-dispatch-thread
有这篇文章:
有人跳了队!偶尔看来,一些挥杆事件在事件队列中以不正确的顺序处理(并且当有人切入队列时没有任何东西让我的血液沸腾)导致奇怪的行为.最好用小代码片段来说明这一点.阅读下面的代码段,仔细考虑您想象的事件发生的顺序.
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
repaint();
doSomething();
}
});
Run Code Online (Sandbox Code Playgroud)
大多数开发人员都认为repaint()方法将导致在doSomething()方法调用之前进行绘制操作.但事实并非如此,对repaint()的调用将创建一个新的绘制事件,该事件将添加到事件队列的末尾.只有当前的Action Event完成后才会处理(调度)此新的paint事件.这意味着将在调度队列上的新Paint Event之前执行doSomething()方法.
这里的关键点是调用repaint()将创建一个新的绘制事件,该事件将被添加到结束事件队列中而不会立即处理.这意味着没有事件跳过队列(我的血液可以保持在正确的温度).
我的问题是,我怎么能强迫的Swing做repaint();之前doSomething();?
此外,如果有方法调用repaint()WITHIN,doSomething();它们将仅在doSomething();完成后执行.有没有办法可以暂停doSomething();中间执行,然后投入reapaint();,完成它,然后恢复doSomething();?
到目前为止我找到的解决方案只有这个(链接),但它并不实用......
那么,你和引用文章的作者在这里忽略了这一点."重绘"方法调用只是通知重绘管理器:
因此,重新绘制的时间并不重要,因为如果您为同一个组件逐个调用大量重绘,您可能甚至都不会注意到它.这也是为什么这样的后续调用可能合并的原因.检查此示例:
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 ();
}
Run Code Online (Sandbox Code Playgroud)
这是您将看到的近似输出(可能因计算机速度,Java版本和许多其他条件而异):
1
Starting repaint calls
2
3
4
5
6
Finishing repaint calls
7
8
Run Code Online (Sandbox Code Playgroud)
"1" - 显示帧时的初始重绘.
"2,3,4 ......" - 由于来自另一个非EDT线程的调用,发生了其他七次重绘.
"但我已经打了100000个重拍,而不是7个!" - 你会说.是的,重新绘制管理器合并了那些在重新绘制队列中相似但同时的内容.这是为了优化重绘和整体UI的加速.
顺便说一句,你不需要从EDT调用重绘,因为它不会执行任何真正的绘画,只是将组件更新排队以备将来使用.它已经是线程安全的方法.
总结一下 - 在执行其他操作之前,您确实需要重新绘制组件(这也可能导致其再次重新绘制)时,应该没有任何情况.只需在重新绘制组件时调用重绘(尽可能使用指定的矩形) - 重绘管理器将完成剩下的工作.除非你在paint方法中加入一些完全错误的计算并且可能会导致很多问题.
| 归档时间: |
|
| 查看次数: |
262 次 |
| 最近记录: |