以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 Java/Eclipse 』  (http://bbs.xml.org.cn/list.asp?boardid=41)
----  SWT和多线程结合使用的问题释疑  (http://bbs.xml.org.cn/dispbbs.asp?boardid=41&rootid=&id=19734)


--  作者:jjplion
--  发布时间:6/18/2005 12:19:00 PM

--  SWT和多线程结合使用的问题释疑
SWT和多线程结合使用的问题释疑

作者:jjp

SWT作为JAVA开源世界的优秀图形库,已经得到了很多java爱好者的青睐。我最近也在使用swt开发一些应用程序。我发现多线程中使用swt需要额外的技巧。

情形:
    单击一个按钮,然后新开一个线程来执行一个复杂的任务。任务执行完时,弹出一个对话框提示任务执行完毕。

示例1:

package threadandui;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class TestSwt1 extends Shell {
        public static Shell shell;
        public static void main(String args[]) {
                try {
                        Display display = Display.getDefault();
                        shell = new TestSwt1(display, SWT.SHELL_TRIM);
                        shell.open();
                        shell.layout();
                        while (!shell.isDisposed()) {
                                if (!display.readAndDispatch())
                                        display.sleep();
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }

        public TestSwt1(Display display, int style) {
                super(display, style);
                createContents();
        }

        protected void createContents() {
                setText("SWT Application1");
                setSize(500, 375);

                final Button button = new Button(this, SWT.NONE);
                button.addSelectionListener(new SelectionAdapter() {
                        public void widgetSelected(SelectionEvent e) {
                                new MyThread().start();
                        }
                });
                button.setBounds(80, 50, 85, 25);
                button.setText("start");
        }

        protected void checkSubclass() {
        }
        
        class MyThread extends Thread{
                public void run(){
                        //complex task
//                        for(int i=0;i < 10000;i++){
//                                System.out.println(i);
//                        }
                        //display a dialog                         
                        MessageBox mb = new MessageBox(shell);
                        mb.setMessage("Task ended!");
                        mb.open();
                }
        }
}

该程序在单击start按钮后会有异常:
Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid thread access
        at org.eclipse.swt.SWT.error(SWT.java:2691)
        at org.eclipse.swt.SWT.error(SWT.java:2616)
        at org.eclipse.swt.SWT.error(SWT.java:2587)
        at org.eclipse.swt.widgets.Widget.error(Widget.java:381)
        at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:284)
        at org.eclipse.swt.widgets.Dialog.checkParent(Dialog.java:154)
        at org.eclipse.swt.widgets.Dialog.<init>(Dialog.java:116)
        at org.eclipse.swt.widgets.MessageBox.<init>(MessageBox.java:81)
        at org.eclipse.swt.widgets.MessageBox.<init>(MessageBox.java:54)
        at threadandui.TestSwt1$MyThread.run(TestSwt1.java:70)

为什么会有异常?没有参考书,没有人指导,你是就此罢休呢,还是刨根问底?我想知道答案,那我该怎么做呢?
请注意,swt是开源的,代码就是你最好的参考书,最好的指导老师!

查看swt源代码:at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:284)

/*245*/        protected void checkWidget () {
        
/*246*/                Display display = this.display;
        
/*247*/                if (display == null) error (SWT.ERROR_WIDGET_DISPOSED);
        
/*248*/                if (display.thread != Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
        
/*249*/                if ((state & DISPOSED) != 0) error (SWT.ERROR_WIDGET_DISPOSED);

/*250*/        }
第248行有判断“display.thread != Thread.currentThread ()”。显然,在我们的示例中他们是不相等的。因为,MessageBox处在新创建的线程中,而display

则处在main线程中。可见我们需要在新线程中创建一个display给MessageBox使用。“示例2”给出了答案。


示例2;
/*
* Created on 2005-5-26
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package threadandui;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

/**
* @author jiangjunping
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class TestSwt2 extends Shell {
        public static Shell shell;
        public static void main(String args[]) {
                try {
                        Display display = Display.getDefault();
                        shell = new TestSwt2(display, SWT.SHELL_TRIM);
                        shell.open();
                        shell.layout();
                        while (!shell.isDisposed()) {
                                if (!display.readAndDispatch())
                                        display.sleep();
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }

        public TestSwt2(Display display, int style) {
                super(display, style);
                createContents();
        }

        protected void createContents() {
                setText("SWT Application2");
                setSize(500, 375);

                final Button button = new Button(this, SWT.NONE);
                button.addSelectionListener(new SelectionAdapter() {
                        public void widgetSelected(SelectionEvent e) {
                                new MyThread().start();
                        }
                });
                button.setBounds(80, 50, 85, 25);
                button.setText("start");
                //
        }

        protected void checkSubclass() {
        }
        
        class MyThread extends Thread{
                public void run(){
                        //complex task
                        for(int i=0;i < 50000;i++){
                                System.out.println(i);
                        }
                        //display a dialog                         
                        Display display = new Display();//new display
                        Shell shell2 = new Shell(display);//added
                        MessageBox mb = new MessageBox(shell2);//use new display created in the current thread
                        mb.setMessage("Task ended!");
                        mb.open();
                        display.dispose();//added
                }
        }
}


好了,程序正常了!



W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
78.125ms