Java 等待AWT重新喷漆完成

Java 等待AWT重新喷漆完成,java,awt,frame,Java,Awt,Frame,我有一个框架,全是一种颜色,但角落里有一些文本。我设置颜色,从显示器上读取颜色,然后根据这些测量值进行一些计算 问题是,调用repaint()会导致帧在我进行测量之后被绘制。我假设这是由于repaint()委托EDT造成的,但由于实际喷漆工作之前/期间发生的测量,我得到了不正确的结果 我最初的想法是让一个监听器完成绘制,但我重新绘制以更新文本的频率要比我更新颜色的频率高很多,我不想听那些事件。我怎么能等到实际的绘画任务完成后再进行测量呢?你能找到的东西真是太棒了 EventQueue.invok

我有一个
框架
,全是一种颜色,但角落里有一些文本。我设置颜色,从显示器上读取颜色,然后根据这些测量值进行一些计算

问题是,调用
repaint()
会导致
帧在我进行测量之后被绘制。我假设这是由于
repaint()
委托EDT造成的,但由于实际喷漆工作之前/期间发生的测量,我得到了不正确的结果


我最初的想法是让一个监听器完成绘制,但我重新绘制以更新文本的频率要比我更新颜色的频率高很多,我不想听那些事件。我怎么能等到实际的绘画任务完成后再进行测量呢?

你能找到的东西真是太棒了

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {

        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
            @Override
            public void eventDispatched(AWTEvent event) {

                PaintEvent pe = (PaintEvent) event;

                String type = "";
                if (pe.getID() == PaintEvent.PAINT) {
                    type = "PAINT";
                } else if (pe.getID() == PaintEvent.PAINT_FIRST) {
                    type = "PAINT_FIRST";
                } else if (pe.getID() == PaintEvent.PAINT_LAST) {
                    type = "PAINT_LAST";
                } else if (pe.getID() == PaintEvent.UPDATE) {
                    type = "UPDATE";
                }

                System.out.println(type + "; pe.UpdateRec = " + pe.getUpdateRect() + "; pe.component = " + pe.getComponent());

            }
        }, AWTEvent.PAINT_EVENT_MASK);

        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(200, 200);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);


    }
});
现在,因为重新绘制请求可以快速、灵活地进行,我很想在最后一个请求完成后不久就会触发一个小的“延迟”

private Timer updateTimer;

// ...

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {

        updateTimer = new Timer(250, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // Update compulations here...
            }
        });
        updateTimer.setRepeats(false);
        updateTimer.setCoalesce(true);

        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

            @Override
            public void eventDispatched(AWTEvent event) {
                updateTimer.restart();
            }
        }, AWTEvent.PAINT_EVENT_MASK);
    }
}
这样做的目的是在最后一次重新绘制请求和编译开始之间留出至少250毫秒的时间。你可能想玩弄一下这些价值观,看看什么适合你

更新

你也可以试试

绘制此组件中的指定区域及其所有 与区域重叠的子体,立即

很少需要调用此方法。在大多数情况下,这更重要 调用重新绘制非常有效,这会延迟实际绘制,并且可以 将冗余请求折叠为单个绘制调用。这种方法是可行的 如果需要在当前事件发生时更新显示,则此选项非常有用 被派遣


我知道这是一个旧线程,但如果有人正在搜索这个问题的答案,有一个名为的方法,可以在AWT调度线程上与当前线程同步运行任务。请注意,如果您需要在事件调度线程内执行此操作,则无法执行此操作。

您可以围绕匿名锁对象同步线程,以使一个线程等待另一个线程。恕我直言,我认为您不能(可靠地)执行此操作。您可以尝试使用
SwingUtilities.invokeLater(Runnable)
在调用repaint后将计算放在EDT的末尾,但不能保证已经在EDT上放置了重新绘制请求…@Vulcan,但我对EDT没有任何控制权,是吗?我想从实际的角度来看,EDT可能是FIFO,但从正确性的角度来看,我能保证吗?@MadProgrammer如果对
repaint()
的调用已经完成,那么我就不能保证它已经提交给EDT了吗?尽管我们仍然存在EDT执行顺序错误的问题。@AndyShulman No。重新绘制请求可能会合并以减少重新绘制事件的数量。注意:如果在处理初始重绘请求之前组件上发生了多次重绘()调用,则多个请求可能会折叠为一次更新()调用。确定何时应折叠多个请求的算法取决于实现。如果多个请求被折叠,则生成的更新矩形将等于折叠请求中包含的矩形的并集。我知道您在这里尝试执行的操作,但是您确定它们将以正确的顺序放置在EDT中吗?一些测试表明,调用
repaint()
一次会产生对我的
paint()
方法的5个调用,我不知道这些调用是同步的还是附加到事件队列的末尾。因为可以合并重绘请求,无法保证它们会按照您要求的顺序出现。那么,我不确定您的解决方案实际如何工作。它似乎是围绕着“在代码中延迟一段时间,并期待最好的结果”展开的。我错了吗?有点。延迟的关键是您不会对每个绘制事件做出响应(因为您可能会收到几十个与同一个更新请求相关的事件)。我们的想法是引入一个小的延迟,以允许EDT空闲(或者至少是在这种情况下重新绘制的请求)。这是我认为你将接近“油漆结束”的周期。除非您希望处理每个绘制事件,但您需要在收到事件通知以及实际绘制调用发生时进行测试……您遇到的另一个问题是,“重新绘制”并不是生成绘制请求的唯一方式。Java可能正在响应来自操作系统的请求,例如鼠标悬停、窗口移动和更改。。。