Java 事件调用器排序

Java 事件调用器排序,java,swing,awt,event-dispatch-thread,Java,Swing,Awt,Event Dispatch Thread,EventQueuejavadoc声明,排队事件必须按顺序发送 Runnables与EventQueue.invokeLater一起排队是否正确保证在后续用户事件(例如MouseEvent)之前调度?换句话说,如果用户事件发生在EventQueue.invokeLater之后,那么事件处理程序可以在排队的Runnable之前执行吗 谢谢 API文档声明事件是 与它们排队的顺序相同 但是如果你检查源代码,你会发现情况并非总是如此,尽管它在大多数情况下基本上是正确的。也许最好解释一下你想做什么。一般

EventQueue
javadoc声明,排队事件必须按顺序发送

Runnable
s与
EventQueue.invokeLater
一起排队是否正确保证在后续用户事件(例如
MouseEvent
)之前调度?换句话说,如果用户事件发生在
EventQueue.invokeLater
之后,那么事件处理程序可以在排队的
Runnable
之前执行吗


谢谢

API文档声明事件是

与它们排队的顺序相同


但是如果你检查源代码,你会发现情况并非总是如此,尽管它在大多数情况下基本上是正确的。

也许最好解释一下你想做什么。一般来说,事件调度系统的设计使您不必知道或担心其内部。如果您正在编写直接更新UI的事件处理程序,那么不使用Runnable并内联执行更新可能是有意义的。但是,如果您的事件处理程序执行某些计算或处理需要不确定的时间,那么您可能希望使用一个线程,该线程最终通过Swing.invokeLater调用Runnable来执行UI更新。需要知道事件分派时的顺序意味着您正试图在逻辑中构建可能属于其他地方的假设

对于EG,考虑一个鼠标点击事件处理程序,它在线程中执行繁重的处理(网络下载或DBMS查询),然后更新UI中的文本标签。您可能希望确保处理和UI更新在用户单击UI上其他位置之前进行,以避免处理单击的模糊性。在这种情况下,您可能会在初始鼠标单击事件中立即禁用UI或UI的某些可单击部分,以便UI保持响应,但在完全处理原始单击事件之前,保护onMouse处理程序不被重新输入。(请原谅下面的代码片段,因为我已经完成Swing多年了,它更像是伪代码。)


这里的想法是编写逻辑,这样它就不依赖于事件发送的随机顺序,而是承认处理可能比下一个传入的鼠标事件花费更长的时间,并为这种时间安排。一个微妙的改进是,还可以绘制一个进度指示器或进度微调器,以指示用户正在完成工作。

否。但必须依赖于用户输入事件的顺序,这表明设计存在问题。如果您正在调度一个事件,那么许多其他输入事件可能已经到达队列。javadoc说:导致runnable在系统EventQueue的调度线程中调用其run方法。这将在处理所有挂起事件后发生。(我强调)我不清楚那句话。它是否仅指当前正在处理的事件,还是指在enqued Runnable之后提交的挂起事件?事件究竟何时变为挂起?当它们从队列中被调度时,或在它们排队时。事件是否像InvocationEvents一样加入队列,或者InvocationEvents和Runnable通常在后续执行?当事件在EventQueue上且尚未调度时,事件处于挂起状态。因此,在调度一个事件的过程中,其他几个事件可能已经在等待调度。然后,您将尝试推送InvocationEvent,该事件将在所有挂起事件被调度后运行。无论如何,您不必依赖于此。AWTEvents是否像Runnable中的InvocationEvents一样排队,或者它们是否立即被调度。awteEvents有单独的方法,即dispatchEvent()和postEvent(),我不确定它们是否在处理之前将事件排队?无法立即调度。事件在AWT事件调度线程(EDT)上调度。调用线程不阻塞。事件始终处于队列中。事件与
postEvent
一起排队,然后在EDT中一次一个地排队并发送到
dispatchEvent
。@user643011在大多数情况下,所有事件(在屏幕上)都是在一分钟内可视地完成的。我有一个后台线程,它禁用部分UI。直到现在,我使用invokeAndWait关闭UI,并保证在后台线程完成时它将被关闭。最近我重构了后台线程,因此它使用invokeLater而不是invokeAndWait来避免死锁的可能性,并希望检查在完成的线程上禁用UI的保证是否仍然有效。然而,我可能不得不重新考虑这一点,因为即使这样,当前仍可能有一个用户事件正在处理中,并且后台线程可能会在此之前完成。非常感谢。如果我理解正确,您的后台线程是否使用了invokeAndWait?这与我上面的建议不同。不要在后台线程中执行关闭,而是将其作为事件处理程序中的第一件事来执行。然后,后台线程将使用invokeLater重新启用UI,这是它在完成之前做的最后一件事。请重温一下我上面的示例,其中我将setEnable(false)作为事件处理程序中的第一件事,而将invokeLater中的setEnable(true)作为runnable中的最后一件事。事件处理程序应该在生成后台线程之前立即禁用UI。后台线程不应该关心何时处理Swing事件,因为事件处理程序已经禁用了UI。它只是继续做它必须做的事情,然后发布一个runnable,当它完成时重新启用UI。谢谢你接受我的回答。祝你重构状态机好运。这听起来相当复杂。我不知道我为什么要在事件处理程序中执行setEnable(false)
void setUIEnabled(boolean enable) {
   for(Button eachUIButton : getAllClickableButtons()) {
      eachUIButton.setEnabled(enable);
   }
}

void onMouseClick(MouseEvent event) {
   setUIEnabled(false);
   new Thread(
      new Runnable() {
         public void run() {
            final String result = doLengthyProcessing();
            enableRunnable = new Runnable() {
               public void run() {
                  setUIEnabled(true);
                  updateTextLabelFromLengthyProcess(result);
               }
            };
            Swing.invokeLater(enableRunnable);
         }
      }
   ).start();
}