Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在事件分派线程上运行类的所有方法_Java_Swing_Event Dispatch Thread - Fatal编程技术网

Java 如何在事件分派线程上运行类的所有方法

Java 如何在事件分派线程上运行类的所有方法,java,swing,event-dispatch-thread,Java,Swing,Event Dispatch Thread,我创建了一个Swing组件,它有几个方法。我希望该类的所有方法都在Swing事件调度线程EDT上运行,而调用方在工作线程上。我目前想到的唯一解决办法是: 对于此类中的每个方法: public void a(params) 我应该将其重命名为: private void aOnEDT(params) 并添加另一种方法: public void a(params) { SwingUtilities.invokeAndWait(new Runnable(){ public

我创建了一个Swing组件,它有几个方法。我希望该类的所有方法都在Swing事件调度线程EDT上运行,而调用方在工作线程上。我目前想到的唯一解决办法是:

对于此类中的每个方法:

public void a(params)
我应该将其重命名为:

private void aOnEDT(params)
并添加另一种方法:

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

但这不是很恶心吗?我应该如何执行此操作?

每当您希望在事件调度线程上执行某些操作时,都应该使用

从Javadoc中摘录:

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


每当您希望在事件分派线程上执行某些操作时,都应该使用

从Javadoc中摘录:

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


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

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


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


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


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

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


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


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


您可以测试当前是否正在EDT上进行调用,并将Runnable放入SwingUtilites.invokeLater(如果不是):

public void myMethod() {
       if (SwingUtilities.isEventDispatchThread()) {
            //... your code
       } else {
           SwingUtilities.invokeLater(
                  new Runnable(){
                     public void run() {
                           myMethod();
                     }
                  });
       {
  }                   

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

您可以测试当前是否在EDT上进行调用,如果不是,则将Runnable放入SwingUtilites.invokeLater:

public void myMethod() {
       if (SwingUtilities.isEventDispatchThread()) {
            //... your code
       } else {
           SwingUtilities.invokeLater(
                  new Runnable(){
                     public void run() {
                           myMethod();
                     }
                  });
       {
  }                   

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

使用“完成”方法更新GUI组件。使用donInBackground方法进行后台工作。

使用done方法更新GUI组件。用donInBackground方法做背景工作。

我们完成这项工作的一种方法是使用AspectJ。样板代码在编译过程中被注入到所有用@OnEDT注释的方法中。生成的代码很薄,非常方便

显然,我们必须为此创建注释、切入点和方面,但这几乎是微不足道的

如果您感兴趣,这里有几个相关链接:


我们实现这一点的一种方法是使用AspectJ。样板代码在编译过程中被注入到所有用@OnEDT注释的方法中。生成的代码很薄,非常方便

显然,我们必须为此创建注释、切入点和方面,但这几乎是微不足道的

如果您感兴趣,这里有几个相关链接:


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

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

为了避免类的每个方法中存在的不好之处,如果类实现了公共接口,您可以使用来执行公共invokeAndWait设置,与实现方法本身的位置不同

实现一个代理,该代理将处理所有样板代码,以检查事件分派线程并调用invokeAndWait 创建代理实例并在其上调用方法,而不是直接在实现类上。 因为这种方法包含了更多的代码,所以它实际上只适用于您的实现类中有大量方法要确保在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;
    }
}
这就是你想要的 ld使用代理:

// 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 );

为了避免存在于类的每个方法中的不好之处,如果类实现了公共接口,则可以使用来执行公共invokeAndWait设置,与实现方法本身的位置不同

实现一个代理,该代理将处理所有样板代码,以检查事件分派线程并调用invokeAndWait 创建代理实例并在其上调用方法,而不是直接在实现类上。 因为这种方法包含了更多的代码,所以它实际上只适用于您的实现类中有大量方法要确保在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 );


谢谢你的回复。难道没有一种解决方案可以在不改变当前和未来所有方法的情况下适用于所有方法吗?@mhosenof我想不出一种。这是我能想到的最好的解决办法。如果你像我一样格式化它,它只需要额外的两行。@mohsenof通常情况下,人们不希望每个方法都在EDT上运行,因为如果EDT上发生太多事情,它可能会导致GUI运行缓慢。谢谢你的回复。难道没有一种解决方案可以在不改变当前和未来所有方法的情况下适用于所有方法吗?@mhosenof我想不出一种。这是我能想到的最好的解决办法。如果你像我一样格式化它,它只需要额外的两行。@mohsenof通常情况下,人们不希望每个方法都在EDT上运行,因为如果EDT上发生太多事情,它可能会导致GUI运行缓慢。嗯,这是确保方法在EDT上执行的好方法。这在开发程序时非常有用,但从长远来看,你不应该依赖于此,而是应该意识到哪些呼叫已经在EDT上,哪些没有-这会增加很多混乱,而且-我不想提及性能,但如果以每秒数百次或更多的速度进行,则会带来很大的开销。嗯,确保方法在EDT上执行的好方法。这在开发程序时非常有用,但从长远来看,你不应该依赖于此,而是应该意识到哪些调用已经在EDT上,哪些没有-这会增加很多混乱,而且-我不想提及性能,但如果它以每秒数百次或更多的速度进行,则会带来很大的开销。从他的问题来看,他似乎已经在使用工作线程。从他的问题来看,他似乎已经在使用工作线程了。问题是为什么突然调用这些方法?通常,当GUI上发生某个事件(如ActionEvent或鼠标单击)时,会执行代码。如果是这种情况,则默认情况下,代码将在EDT上自动执行。如果您有调用这些方法的其他逻辑,那么只有origianl方法需要包装在invokeLater中。所有的工作线程都有一个持久的作业复制文件,它会通知侦听器发生了什么:成功、失败、进度等等。我的组件是侦听器之一,所以我的组件的几个方法都会被工作线程调用。问题是为什么突然调用这些方法?通常,当GUI上发生某个事件(如ActionEvent或鼠标单击)时,会执行代码。如果是这种情况,则默认情况下,代码将在EDT上自动执行。如果您有调用这些方法的其他逻辑,那么只有origianl方法需要包装在invokeLater中。所有有一个工作线程,它有一个持久的作业复制文件,它会通知侦听器发生的事情:成功、失败、进度等。我的组件是侦听器之一,所以我的组件的几个方法将由工作线程调用。我刚刚尝试了这个,它不会运行,因为Java 1.7/8 awt类加载器在您尝试加载带有Java.awt包的类时会抛出SecurityException:使用不同的包会破坏所需的接口。我刚刚尝试过这个,它不会运行,因为如果您试图用Java.awt包加载类,Java 1.7/8 awt类加载器会抛出SecurityException:使用不同的包会破坏所需的接口。