如何使用标准窗口小部件工具包中的UI线程同步代码

时间:2010-08-02 10:05:53

标签: java swt

当我尝试运行我的代码时,我不断收到一个说“无效线程访问”的SWTException。我读了,问题似乎是有代码试图从UI线程外部访问SWT对象。具体来说,我有一个表格小部件,我添加了一个选择监听器。这是选择监听器的代码。

rosterTable.addSelectionListener(new SelectionAdapter()

    {
        public void widgetSelected(final SelectionEvent event)
        {

              createChat(connection,event);


        }

            });

以下是createChat方法的代码:

public void createChat(final XMPPConnection connection,final SelectionEvent event)
{
    Display.getDefault().syncExec(new Runnable()        
    {
        public void run()
        {
            String s = event.item.toString();
            int length = event.item.toString().length();
            ClassView cv = new ClassView(connection,s.substring(11,length -1),null);
        }
    });

正如你所看到的那样,我已经尝试过将UI线程之外的代码同步到UI线程,将它包装在syncExec方法中,但是当选择表项时我仍然得到异常,这让我相信我把syncExec部分放在了错误的地方。

我还认为问题可能来自于在createChat方法中实例化的ClassView对象使用SWT小部件,但我不确定。

有谁知道syncExec代码应该去哪里?

或者,如果我完全错了,我该如何解决?

更新

我做了你说的话,不幸的是我仍然得到了例外,我对代码进行了一些重新设计,所以它现在看起来有点不同,我认为不应该有任何区别但是以防万一这里是侦听器的代码:

 rosterTable.addSelectionListener(new SelectionAdapter()

    {
        public void widgetSelected(final SelectionEvent event)
        {

           selectedUser = event.item.toString();
           System.out.println(selectedUser);
           rm.createChat(selectedUser);

        }






    });

这里是现在不同类的方法的代码:

public void createChat(String item)
{
    int length = item.length();
    Chatter c = new Chatter(connection,item.substring(11,length-1));

}

以下是异常的堆栈跟踪:

org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:3884)
at org.eclipse.swt.SWT.error(SWT.java:3799)
at org.eclipse.swt.SWT.error(SWT.java:3770)
at org.eclipse.swt.widgets.Display.checkDisplay(Display.java:721)
at org.eclipse.swt.widgets.Display.create(Display.java:783)
at org.eclipse.swt.graphics.Device.<init>(Device.java:135)
at org.eclipse.swt.widgets.Display.<init>(Display.java:454)
at org.eclipse.swt.widgets.Display.<init>(Display.java:445)
at instantmessengerplugin.ClassView.<init>(ClassView.java:33)
at instantmessengerplugin.Chatter.<init>(Chatter.java:20)
at instantmessengerplugin.RosterManager.createChat(RosterManager.java:48)
at instantmessengerplugin.RosterView$1.widgetSelected(RosterView.java:103)
at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:228)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3880)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3473)
at instantmessengerplugin.RosterView.<init>(RosterView.java:158)
at instantmessengerplugin.Connection.connect(Connection.java:110)
at instantmessengerplugin.Connection$1.widgetSelected(Connection.java:65)
at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:228)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3880)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3473)
at instantmessengerplugin.Connection.<init>(Connection.java:77)
at instantmessengerplugin.Connection.main(Connection.java:119)

2 个答案:

答案 0 :(得分:0)

您正在从UI线程中调用syncExec(),这绝对是一个问题。

所有SWT事件都会在UIThread上触发,因此当您从createChat()内拨打widgetSelected()时,您已经在UIThread上。在createChat()之内,您将再次尝试阻止UIThread导致问题。

尝试取消对此syncExec()的调用,并报告正在发生的事情。如果仍有异常,请包括堆栈跟踪。

如果您正在创建一个简单的SWT程序,通常您不必担心UI线程,因为大多数简单的应用程序都可以响应事件而工作,因此在UI线程上处理业务逻辑。当你开始产生线程时(或者使用java.util.concurrent之类的东西,在幕后为你设置线程),你必须开始担心UI线程,以便让你的ui更具响应性。

答案 1 :(得分:0)

我解决了这个问题。异常来自这样一个事实:在ClassView中我试图创建类SWT显示的实例,当时已经存在另一个实例。该平台只允许任何一个人打开。

我更改了代码,因此只使用了一个显示,异常消失了。

感谢您的帮助。