首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >EDT队列切割

EDT队列切割
EN

Stack Overflow用户
提问于 2013-08-05 15:37:17
回答 2查看 305关注 0票数 3

以下是一篇文章:

有人插队了!有时会出现一些swing事件在事件队列中按不正确的顺序处理(没有什么会像某个人进入队列时那样让我的血液沸腾),从而导致奇怪的行为。这最好用一个小的代码片段来说明。阅读下面的片段,仔细考虑一下您所设想的事件将发生的顺序。

代码语言:javascript
复制
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();

到目前为止,我找到的唯一解决方案是这(链接),但实际上并不实用.

EN

回答 2

Stack Overflow用户

发布于 2013-08-05 15:56:29

好吧,你和这篇文章的作者都漏掉了这一点。“重新绘制”方法调用简单地通知重绘管理器:

  1. 有一个组件需要重新绘制(在该组件上,您称之为“重新绘制”)。
  2. 应该用(x,y,w,h)剪辑重新绘制它(如果您调用"repaint“w/o,指定rect -it将是整个组件边界,(0,0,w,h))

因此,在什么时候进行重绘并不重要,因为如果您为同一个组件一个接一个地调用大量重绘,您甚至可能不会注意到它。这也是为什么这样的后续调用可能会被合并。请检查此示例:

代码语言:javascript
复制
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版本和许多其他条件而有所不同):

代码语言:javascript
复制
1
Starting repaint calls
2
3
4
5
6
Finishing repaint calls
7
8

"1“-框架显示时的初始重绘。

“2,3,4.”

“但是我叫了100000重漆,不是7!”--你会说。是的,重绘管理器合并了那些相似的,同时在重绘队列中。这是为了优化重绘和加速UI的整体。

顺便说一句,您不需要从EDT调用重新绘制,因为它不执行任何真正的绘制,只需要为将来的组件更新排队。它已经是线程安全的方法了。

总结--在执行其他操作之前,不应该有真正需要重新绘制组件的情况(这也会导致组件重新绘制)。只需在需要重新绘制组件时调用重绘(在可能的情况下使用指定的矩形)-重新绘制管理器将完成其余的操作。这很好,除非你把一些计算放在油漆方法中,这是完全错误的,可能会导致很多问题。

票数 6
EN

Stack Overflow用户

发布于 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对象创建自己的图形对象,如果您想要截图并将其写入图片文件)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18062126

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档