Java SWT:包装syncExec和asyncExec以清理代码

时间:2010-06-03 19:40:41

标签: java user-interface swt

我有一个使用SWT作为工具包的Java应用程序,我厌倦了更新GUI元素所需的所有丑陋锅炉板代码。

只是设置一个禁用按钮启用我必须经历这样的事情:

shell.getDisplay().asyncExec(new Runnable() {
    public void run() {
        buttonOk.setEnabled(true);
    }
});

我更喜欢保持我的源代码尽可能平坦,但我需要一个高达3个缩进级别来做一些简单的事情。

有什么方法可以包装吗?我想要一个类:

public class UIUpdater {
    public static void updateUI(Shell shell, *function_ptr*) {
        shell.getDisplay().asyncExec(new Runnable() {
           public void run() {
              //Execute function_ptr
           }
        });
    }
}

可以像这样使用:

UIUpdater.updateUI(shell, buttonOk.setEnabled(true));

像这样的东西对于隐藏SWT似乎认为有必要做任何事情的可怕混乱都是很好的。

据我了解,Java无法做函数指针。但Java 7将有一个名为Closures的东西应该是我想要的。但与此同时,我可以做任何事情来将函数指针或回调传递给另一个要执行的函数吗?

顺便说一句,我开始认为在Swing中重做这个应用程序是值得的,而且我不必忍受这个丑陋的废话和SWT的非跨平台性。 / p>

3 个答案:

答案 0 :(得分:4)

我的SWT代码中存在类似的问题。

我写了一个只有asyncExec和syncExec方法的基类。我有一个方法用于我想要调用的每个GUI方法。

我的非GUI线程类扩展了基类。

所以在非GUI线程类中,我有一个像setEnabled(shell, true)

这样的调用

在基类中,我将定义一个public void setEnabled(Shell shell, boolean flag)方法,该方法将包含第一个示例中的代码。

答案 1 :(得分:2)

我前段时间在一个封闭的源项目中解决了这个问题。我的API工作原理如下:

SWTUtils.asyncExec(display).on(this.getClass(), this).runInUIThread(123);

此调用将使用参数runInUIThread(.)在实例this上运行方法123。这里需要的杂波是参数this.getClass()

你重写的例子:

SWTUtils.asyncExec(shell.getDisplay()).on(Button.class, buttonOk).setEnabled(true);

我的实现使用CGLib为给定的类创建动态代理。此代理由on(.)返回,方法调用及其参数被记录并传递给display.asyncExec(.)。我使用Objenesis来实例化代理。

您可能会惊讶于没有可察觉的性能影响。由于代理被缓存,并且在java 1.6中调用实际方法所需的反射API变得非常快,我甚至将它用于事件监听器。

显然这是一个相当疯狂的解决方案;)我无法发布它,但如果你像所有这些匿名的内部类一样生气,你可能想要去实现它。实际上这不是太多的代码。

答案 2 :(得分:2)

你说你想要类似的东西:

public class UIUpdater {
    public static void updateUI(Shell shell, *function_ptr*) {
        shell.getDisplay().asyncExec(new Runnable() {
           public void run() {
              //Execute function_ptr
           }
        });
    }
}

你不能拥有它的事实不是SWT的功能,它是Java作为编程语言的功能。 Java缺乏高阶函数和闭包可以防止你创建一个好的DSL来隐藏那些残酷的东西,所以除了你改变语言之外,你收到的其他答案都和其他答案一样好。

现在,如果您使用像Scala这样的语言,我认为答案有很大不同。您可能会创建一些模仿控制结构的函数,以确保您的SWT调用将在主SWT显示线程上执行。

类似的东西:

val enabled = model.isEditable
Swt {
  text.setEnabled(enabled);
  composite.refresh();
}