我创建了一个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); } }); }
但这不是很讨厌吗?
我该怎么做?
我希望有人帮助我解决这个问题。
谢谢
答案 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将冻结并变得无响应。
答案 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
设置实施方法本身。
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 );