如何在Event Dispatch Thread上运行类的所有方法

时间:2010-06-23 14:36:15

标签: java swing event-dispatch-thread

我创建了一个Swing组件,它有几种方法 现在我希望这个类的所有方法都在Event Dispatch Thread(EDT)上运行,而调用者在Worker线程上运行。 目前我心中唯一的解决方案就是:
对于每种方法

public void a(params)  

在这个课上,我应该将其重命名为

private void aOnEDT(params)  

并添加另一种方法

 
public void a(params){
    SwingUtilities.invokeAndWait(new Runnable(){
        public void run() {
            aOnEDT(params);
        }
    });
}

但这不是很讨厌吗?

我该怎么做?

我希望有人帮助我解决这个问题。

谢谢

7 个答案:

答案 0 :(得分:2)

您可以测试当前是否在EDT上进行通话,如果不是Runnable则将SwingUtilites.invokeLater()放入public void myMethod() { if (SwingUtilities.isEventDispatchThread()) { //... your code } else { SwingUtilities.invokeLater( new Runnable(){ public void run() { myMethod(); } }); { }

{{1}}

如果您在EDT上,这将保持方法运行,而不会将其放在事件队列的末尾。

答案 1 :(得分:1)

每当您想要在事件发送线程上执行某些操作时,您应该使用SwingUtilities.invokeLater(Runnable doRun)

从Javadoc中提取:

  

导致执行doRun.run()   在AWT事件上异步   调度线程。这将发生   在所有未决的AWT事件发生之后   处理。应该使用这种方法   当应用程序线程需要时   更新GUI。

答案 2 :(得分:1)

在您需要在EDT上运行的所有方法中,您应该将方法体包装在以下代码中:

SwingUtilities.invokeLater(new Runnable(){public void run(){


    // All code placed in here will be ran asynchronously on the EDT


}});

这将导致方法中的所有内容在EDT上运行。因为您在EDT上运行代码,所以不应该做任何会阻塞很长时间的事情。 (文件IO,长计算等)否则您的GUI将冻结并变得无响应。

invokeLater() javadocs

答案 3 :(得分:0)

使用SwingWorker并在done()方法中更新GUI组件。后台在donInBackground()方法中工作。

答案 4 :(得分:0)

我们完成的一种方法是使用AspectJ。在编译期间将样板代码注入到使用@OnEDT注释的所有方法中。结果代码很简单,非常方便。

我们不得不为此创建注释,切入点和方面,但这几乎是微不足道的。

如果您有兴趣,可以使用以下几个相关链接:

http://www.eclipse.org/aspectj/

http://www.eclipse.org/ajdt/EclipseCon2006/

http://www.cs.wustl.edu/~mdeters/doc/slides/aspectjtutorial.pdf

答案 5 :(得分:0)

感谢您的所有回复。 最后,我们(好吧,我的朋友不是我!)围绕我们的组件创建了一个包装类。这个包装器接收所有调用,创建一个runnable(我们调用实际方法的内部run())并将此runnable发送到invokeLater()。
所有这些似乎都没有使用反射库那么复杂。 起点是java.lang.reflect.Proxy类,它动态地创建接口的实例。

答案 6 :(得分:0)

为了避免课程中每个方法中存在的“肮脏”,如果您的课程实现了公共界面,您可以使用Proxy执行与您分开的常见invokeAndWait设置实施方法本身。

  1. 实施代理InvocationHandler,该代理将处理所有样板代码以检查事件派发线程并调用invokeAndWait
  2. 创建代理的实例并在其上调用方法,而不是直接在您的实现类上。
  3. 由于这种方法在前期包含了更多的代码,因此只有当您的实现类具有大量希望确保在EDT上运行的方法时,它才真正适用。

    完整示例:

    public class ImplClass implements ClassInterface {
        public void a( String paramA, int paramB ) {
            // do something here...
        }
    }
    
    public interface ClassInterface {
        void a( String paramA, int paramB );
    }
    
    public class MyHandler implements InvocationHandler {
        private ClassInterface implClassInstance;
        public MyHandler( ImplClass implInstance ) {
            this.implClassInstance = implInstance;
        }
        public Object invoke( Object proxy, final Method method, final Object[] args ) throws Throwable {
            if( SwingUtilities.isEventDispatchThread() ) {
                method.invoke( implClassInstance, args );
            }
            else {
                SwingUtilities.invokeAndWait( new Runnable() {
                    public void run() {
                        try {
                            method.invoke( implClassInstance, args );
                        }
                        catch( RuntimeException e ) {
                            throw e;
                        }
                        catch( Exception e ) {
                            throw new RuntimeException( e );
                        }
                    }
                } );
            }
            return null;
        }
    }
    

    以下是您使用代理的方式:

    // create the proxy like this:
    ImplClass implInstance = new ImplClass();
    MyHandler handler = new MyHandler(implInstance);
    ClassInterface proxy = (ClassInterface) Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[] { ClassInterface.class }, handler );
    // ...
    // call the proxy like you would an instance of your implementation class
    proxy.a( "paramAValue", 123 );