Java 在执行所有鼠标事件侦听器后调用代码

Java 在执行所有鼠标事件侦听器后调用代码,java,event-listener,Java,Event Listener,我已经创建了一个面板,在上面绘制了一组对象。每个对象都作为鼠标事件侦听器添加到面板中。正如我所知,事件发生后,监听器会收到通知,代码可能会(或正在?)在多个线程中执行。是否可以附加一个自定义代码,该代码将在所有侦听器执行完代码后执行?我相信您需要的是使用SwingUtilities.invokeLater()方法,该方法将在处理完所有其他GUI事件后调用事件调度线程上的可运行实例。我相信您需要的是使用SwingUtilities.invokeLater()方法,该方法将在处理所有其他GUI事件后

我已经创建了一个面板,在上面绘制了一组对象。每个对象都作为鼠标事件侦听器添加到面板中。正如我所知,事件发生后,监听器会收到通知,代码可能会(或正在?)在多个线程中执行。是否可以附加一个自定义代码,该代码将在所有侦听器执行完代码后执行?

我相信您需要的是使用
SwingUtilities.invokeLater()
方法,该方法将在处理完所有其他GUI事件后调用事件调度线程上的可运行实例。

我相信您需要的是使用
SwingUtilities.invokeLater()
方法,该方法将在处理所有其他GUI事件后调用事件调度线程上的可运行实例。

在同一线程(事件调度线程)中执行

要做您想要做的事情,您只需添加一个额外的侦听器,并让该侦听器调用类的“executeLater”方法

它所做的是等待EDT线程完成通知,然后调用代码

要测试它,请添加此侦听器并查看它的功能:

 class MouseListener extends MouseAdapter {
     public void mouseClicked(MouseEvent e)  {
           // System.out.println("If uncommented this would be invoked with the rest of the listners");
           SwingUtilities.invokeLater( new Runnable() {
                public void run() {
                    System.out.println("Invoked after all the listeners were notified");
                }
            }
     }
 }

当然,你拥有的是一个鼠标侦听器。所有其他侦听器的概念都是相同的。

在同一线程(事件调度程序线程)中执行

要做您想要做的事情,您只需添加一个额外的侦听器,并让该侦听器调用类的“executeLater”方法

它所做的是等待EDT线程完成通知,然后调用代码

要测试它,请添加此侦听器并查看它的功能:

 class MouseListener extends MouseAdapter {
     public void mouseClicked(MouseEvent e)  {
           // System.out.println("If uncommented this would be invoked with the rest of the listners");
           SwingUtilities.invokeLater( new Runnable() {
                public void run() {
                    System.out.println("Invoked after all the listeners were notified");
                }
            }
     }
 }
当然,你拥有的是一个鼠标侦听器。所有其他听众的想法都是一样的。

至于Noel comment:

这种技术可能会遇到的一个问题是,如果特定的侦听器实现提前返回通知,并在单独的线程上执行“带外”工作。在这种情况下,通知调用的结束实际上并不表示侦听器执行的结束。如果这是一个实际的问题(即,您知道并关心其他用户定义的、精心设计的侦听器做这类事情),那么您可能需要改进并重新审视这个问题

使用
SwingUtilities.invokeLater()
可以确保在通知所有侦听器之后执行代码。但是其中一个侦听器可能在单独的线程中执行其工作

如果您需要在所有侦听器不仅收到通知而且完成工作后执行代码,您可以执行以下操作:

伪代码:

如果你有你的听众

 addListener( new Listener() )
 addListener( new Listener() )
 addListener( new Listener() )
 addListener( new ExecuteAtTheEnd() ) 
如果您的所有(或部分)侦听器在不同的线程中执行其工作,则您的
执行结束
可能会在通知结束时执行其代码,但不会在侦听器代码执行结束时执行

那么,你是做什么的

您必须同步某些锁定标志的使用,并执行代码,直到不使用该标志为止

它可能是一个计数器,在侦听器执行时递增,在不执行时递减:

 Listener implements MouseListener 
    +mouseClicked( event: MouseEvent )
        lockFlagCount++ 
        SwingUtilities.invokeLater( 
              someTask() 
        )

    -someTask()
        // perform some long task.
        lockFlag--
然后继续,直到这个标志为false:

  ExecuteAtTheEndListener implements MouseListener 

       + mouseClicked( event: MouseEvent ) 
        SwingUtilities.invokeLater( 
              executeAtTheEnd() 
        )
       - executeAtTheEnd() 
            while( logFlagCount > 0 ) 
                wait()

             if( logFlagCount == 0 ) 
                 // continue with the task.                  
当然,它比我在伪代码中所说的要复杂得多,但如果你处于这种情况,它应该可以工作。

至于Noel评论:

这种技术可能会遇到的一个问题是,特定的侦听器实现是否提前返回通知,并在单独的线程上执行“带外”工作。在这种情况下,通知调用的结束实际上并不表示侦听器执行的结束。如果这是一个实际问题(也就是说,如果您知道并关心其他用户定义的、精心设计的监听器会做这类事情,那么您可能希望改进并重新审视这个问题

使用
SwingUtilities.invokeLater()
可以确保在通知所有侦听器之后执行代码。但是其中一个侦听器可能在单独的线程中执行其工作

如果您需要在所有侦听器不仅收到通知而且完成工作后执行代码,您可以执行以下操作:

伪代码:

如果你有你的听众

 addListener( new Listener() )
 addListener( new Listener() )
 addListener( new Listener() )
 addListener( new ExecuteAtTheEnd() ) 
如果您的所有(或部分)侦听器在不同的线程中执行其工作,则您的
执行结束
可能会在通知结束时执行其代码,但不会在侦听器代码执行结束时执行

那么,你是做什么的

您必须同步某些锁定标志的使用,并执行代码,直到不使用该标志为止

它可能是一个计数器,在侦听器执行时递增,在不执行时递减:

 Listener implements MouseListener 
    +mouseClicked( event: MouseEvent )
        lockFlagCount++ 
        SwingUtilities.invokeLater( 
              someTask() 
        )

    -someTask()
        // perform some long task.
        lockFlag--
然后继续,直到这个标志为false:

  ExecuteAtTheEndListener implements MouseListener 

       + mouseClicked( event: MouseEvent ) 
        SwingUtilities.invokeLater( 
              executeAtTheEnd() 
        )
       - executeAtTheEnd() 
            while( logFlagCount > 0 ) 
                wait()

             if( logFlagCount == 0 ) 
                 // continue with the task.                  

当然,正如我在伪代码中所说的那样,它要复杂得多,但如果您处于这种情况下,它应该可以工作。

@czuk:这种技术可能会遇到的一个问题是,如果某个特定的侦听器实现提前返回通知,并在“带外”执行工作在单独的线程上。在这种情况下,通知调用的结束实际上并不表示侦听器执行的结束。如果这是一个实际问题(也就是说,你知道并关心其他用户定义的、精心设计的监听器会做这类事情,你可能会想改进并重新审视这个问题。@Noel:这是一个很好的观点。尽管监听器在长时间运行的任务(这是可取的)中使用不同的线程这一事实意味着它应该将他自己标记为“准备好接受更多”因此监听器代码实际上已经准备好了。另一种方法是使用共享标志,直到所有代码都准备好了才设置该标志……嗯,让我看看是否可以编写一些代码来更好地解释这一点。@Noel:你是指jvm开始以不同的方式执行监听器代码的情况吗