`

解决SWT中事件响应的线程冲突问题

阅读更多
最近工作中要做一件这样的事情,就是在一个已有的SWT界面上对一些业务层写好的事件做响应,也就是是SWT的组件订阅了某个时间Listener,当事件触发的时候响应的SWT组件会做出一些信息的显示工作。一开始我们的程序是这样写的:我们所期待的那样做出了反应。问题解决了。总结一下也就是 SWT的在对其组件进行操作的时候有一个单线程的约束,直接的赋值方式是行不通的,SWT在*.widget.Display类中提供了两个方法可以间接的在非用户线程的进行图形构件的访问操作,这是通过的syncExec(Runnable)和asyncExec(Runnable)这两个方法去实现的。而方法syncExec()和asyncExec()的区别在于前者要在指定的线程执行结束后才返回,而后者则无论指定的线程是否执行都会立即返回到当前线程。
我们会在一个业务的监听器中将我们需要进行设置(重绘)的SWT组件从其构造函数中传过去:

java 代码
 
  1. ServiceListener serviceListener = new ServiceListener(txtInformation);  


这里做下说明,ServiceListener是我们自己实现的一个实现了javax.management.NotificationListener 接口的Listener ,它必须实现其handleNotification方法,而txtInformation是一个swt.Text的组件。我们想当然的在这个方法中做一些跟SWT有关的操作于是我们将这个Text组件传进去,再在响应事件中对其进行操作。

java 代码
 
  1. public class ServiceListener implements NotificationListener {  
  2.   
  3. public ServiceListener(Text information) {  
  4. // TODO Auto-generated constructor stub  
  5. super();  
  6. txtInformation = information;  
  7. }  
  8.   
  9. Text txtInformation;  
  10.   
  11. public void handleNotification(Notification notification, Object handback) {  
  12.   
  13. ... ....  
  14.   
  15. //比如说我们取到某些值想要把它赋值给我们的SWT组件  
  16.   
  17. String result = "this is a test!";  
  18.   
  19. txtInformation = result;  
  20.   
  21. }  
  22.   
  23. }  


我们期待的是,当我们期待的事件发生后,会触发这个响应事件做出响应,而我们在已有的SWT界面上的TEXT组件的值会发生改变。但事实上事件是触发了,但程序走到 “txtInformation.setText(result); ”这一行的时候无端停住了,并报了个异常。单我们但不跟踪并查看SWT的源代码的时候看到Text组件中的setText方法是这样写的:
java 代码
 
  1. public void setText (String string) { 

  2. checkWidget (); 

  3. if (string == null) error (SWT.ERROR_NULL_ARGUMENT); 

  4. string = Display.withCrLf (string); 

  5. if (hooks (SWT.Verify) || filters (SWT.Verify)) { 

  6. int length = OS.GetWindowTextLength (handle); 

  7. string = verifyText (string, 0, length, null); 

  8. if (string == nullreturn

  9. }  
  10. TCHAR buffer = new TCHAR (getCodePage (), string, true); 

  11. OS.SetWindowText (handle, buffer);  
  12. /* 
  13. * Bug in Windows.  When the widget is multi line 
  14. * text widget, it does not send a WM_COMMAND with 
  15. * control code EN_CHANGE from SetWindowText () to 
  16. * notify the application that the text has changed. 
  17. * The fix is to send the event. 
  18. */  
  19. if ((style & SWT.MULTI) != 0) { 

  20. sendEvent (SWT.Modify);  
  21. // widget could be disposed at this point 



  22. }  


其中checkWidget ();方法引起了我们的注意,进去看看:
java 代码
 
  1. /** 
  2. * Throws an SWTException if the receiver can not 
  3. * be accessed by the caller. This may include both checks on 
  4. * the state of the receiver and more generally on the entire 
  5. * execution context. This method should be called by 
  6. * widget implementors to enforce the standard SWT invariants. 
  7. * 
  8.  
  9. * Currently, it is an error to invoke any method (other than 
  10. isDisposed()) on a widget that has had its 
  11. dispose() method called. It is also an error 
  12. * to call widget methods from any thread that is different 
  13. * from the thread that created the widget. 
  14. * 
  15.  
  16. * In future releases of SWT, there may be more or fewer error 
  17. * checks and exceptions may be thrown for different reasons. 
  18. * 
  19.  
  20. * 
  21. * @exception SWTException 
    •   * 
    •     
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    •  
    • * 
    •     
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    •  
    • *
     
  22. */  
  23. protected void checkWidget () { 

  24. Display display = this.display; 

  25. if (display == null) error (SWT.ERROR_WIDGET_DISPOSED); 

  26. if (display.thread != Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
  27.   
  28. if ((state & DISPOSED) != 0) error (SWT.ERROR_WIDGET_DISPOSED); 

  29. }  

看见没有,事实上这里明显的是不能在多个线程中对同一个SWT组件进行操作,从ibm developerworks上了解到:Java语言本身就提供了多线程机制,这种机制对GUI编程来说是不利的,它不能保证图形构件操作的同步与串行化。SWT采用了一种简单而直接的方式去适应本地GUI系统对线程的要求:在SWT中,通常存在一个被称为"用户线程"的唯一线程,只有在这个线程中才能调用对构件或某些图形API的访问操作。如果在非用户线程中程序直接调用这些访问操作,那么SWTExcepiton异常会被抛出。

那么怎么解决这个问题了,按照developerworks提出的方案,我们对我们的之前写的程序稍微做了一些改进:


java 代码
 
  1. public class ServiceListener implements NotificationListener {  
  2.   
  3. public ServiceListener(Text information) {  
  4. // TODO Auto-generated constructor stub  
  5. super();  
  6. txtInformation = information;  
  7. }  
  8.   
  9. Text txtInformation;  
  10.   
  11. public void handleNotification(Notification notification, Object handback) {  
  12.   
  13. ... ....  
  14.   
  15. //比如说我们取到某些值想要把它赋值给我们的SWT组件  
  16.   
  17. String result = "this is a test!";  
  18.   
  19. //以下是新加的:  
  20.   
  21. txtInformation.getDisplay().asyncExec(new Runnable() {  
  22.   
  23. public void run() {  
  24. txtInformation.setText(result);  
  25. }  
  26. });  
  27.   
  28. }  
  29.   
  30. }  

很好程序如我们所期待的那样做出了反应。问题解决了。总结一下也就是 SWT的在对其组件进行操作的时候有一个单线程的约束,直接的赋值方式是行不通的,SWT在*.widget.Display类中提供了两个方法可以间接 的在非用户线程的进行图形构件的访问操作,这是通过的syncExec(Runnable)和asyncExec(Runnable)这两个方法去实现 的。而方法syncExec()和asyncExec()的区别在于前者要在指定的线程执行结束后才返回,而后者则无论指定的线程是否执行都会立即返回到 当前线程。

enjoying!
分享到:
评论
1 楼 owennet 2008-04-21  
很好,很实在!!

相关推荐

    eclipse从入门到精通

    在Eclipse中集成CVS,可以实现代码的版本管理,包括文件的提交、更新、冲突解决等。通过CVS,团队成员可以协作开发,同时保持代码的完整性和一致性。 **九、SWT组件与事件模型** SWT不仅提供了丰富的组件库,还有...

    Eclipse从入门到精通.pdf

    Eclipse内置了对CVS的支持,开发者可以通过Eclipse直接进行文件的提交、更新、冲突解决等操作,大大提高了团队协作的效率。 ### SWT组件与事件模型 SWT提供了丰富的组件,如按钮、文本框、下拉框等,用于构建用户...

    Eclipse从入门到精通

    解决文件冲突、忽略不必要的文件以及为软件打包版本等操作,都是CVS使用过程中的常见场景。 #### SWT概述与事件模型 SWT不仅提供了丰富的GUI组件,还有一套完整的事件处理机制。了解事件的四种写法以及如何访问类...

    swing eclipse 式 框架源码

    6. **线程管理**:在 Swing 应用中,通常遵循“单线程模型”,所有 GUI 更新应在 Event Dispatch Thread(EDT)上进行,以避免界面更新和用户交互间的冲突。 7. **国际化(i18n)**:Swing 支持国际化,开发者应...

    java面试中重点题目

    1. **菱形继承问题**:当一个类继承自两个或更多的类时,如果这些父类中有相同的方法或属性,那么子类在访问这些成员时就会产生冲突。解决这种冲突通常需要复杂的规则,增加了语言的复杂性和学习成本。 2. **简化...

    Eclipse权威开发指南2.pdf

    8.6.3 使用并发性架构维持对用户的快速响应..... 210 8.6.4 通过功能组管理用户界面..... 210 8.6.5 扩展Workbench集成开发环境..... 211 8.7 本章小结...... 212 8.8 参考文献...... 212 第9章 插件开发入门 213...

    Eclipse权威开发指南3.pdf

    8.6.3 使用并发性架构维持对用户的快速响应..... 210 8.6.4 通过功能组管理用户界面..... 210 8.6.5 扩展Workbench集成开发环境..... 211 8.7 本章小结...... 212 8.8 参考文献...... 212 第9章 插件...

    Eclipse权威开发指南1.pdf

    8.6.3 使用并发性架构维持对用户的快速响应..... 210 8.6.4 通过功能组管理用户界面..... 210 8.6.5 扩展Workbench集成开发环境..... 211 8.7 本章小结...... 212 8.8 参考文献...... 212 第9章 插件...

Global site tag (gtag.js) - Google Analytics