浅谈EventQueue in Swing

开发 后端
本文介绍EventQueue in Swing,包括介绍为什么Modal Dialog(Frame)弹出的时候界面不会死和为什么界面会死掉等。

最近在看多线程的东西,EventQueue in Swing负责所有AWTEvent(以及其子类)的分发,以后如果要定义自己的ProgressBar可能会用到,先记下来。

EventQueue in Swing简单工作原理

简单来讲,在EventQueue中有一个dispatchThread,这是一个线程类,负责事件的分发,当Queue中有事件的时候,它会摘取前面的事件并分发给相应的对象进行处理,等处理完之后再获取下一个,当Queue中没有事件的时候,线程等待。

当有事件触发时,系统会调用EventQueue的push方法将AWTEvent添加到EventQueue的最后,同时唤醒dispatchThread。

为什么界面会死掉

所以可以看到,Swing的事件分发实际上是同步的,并且都是在dispatchThread这个线程中处理的,也就是说是一个事件一个事件处理的,如果有某一个事件处理的时间非常长的时侯,其他事件就会被堵塞在那里,从现象上看得话,就是界面会死掉,如果界面被其他窗口覆盖之后再回到前面的时侯,会变成一片灰色,这是因为PaintEvent被堵塞而不能被分发出去的缘故。

为什么Modal Dialog(Frame)弹出的时候界面不会死

当在处理事件的时侯如果弹出一个Modal Dialog,那么处理方法会停在那里并等待Modal Dialog销毁,这个时候按照上面的分析,dispatchThread也会停在那里,这样的话其他事件也不会被分发,那么界面也应该会死掉才对。实际上在等待Modal Dialog销毁的过程中,如果能够保证事件可以顺利地分发出去的话,界面当然就不会死。先来看这个例子。

  1. packageeventqueue;  
  2.  
  3. importjava.awt.AWTEvent;  
  4. importjava.awt.ActiveEvent;  
  5. importjava.awt.Component;  
  6. importjava.awt.EventQueue;  
  7. importjava.awt.MenuComponent;  
  8. importjava.awt.event.ActionEvent;  
  9. importjava.awt.event.ActionListener;  
  10.  
  11. importjavax.swing.JButton;  
  12. importjavax.swing.JDialog;  
  13.  
  14. publicclassTestEvent{  
  15. publicstaticvoidmain(String[]args){  
  16. finalJDialogdlg=newJDialog();  
  17. dlg.setTitle("TestEventQueue");  
  18. JButtonbtn=newJButton("Test");  
  19. dlg.getContentPane().add(btn);  
  20. btn.addActionListener(newActionListener(){  
  21. publicvoidactionPerformed(ActionEvente){  
  22. longnow=System.currentTimeMillis();  
  23. EventQueuetheQueue=dlg.getToolkit().getSystemEventQueue();  
  24. System.out.println("atleast5000millis");  
  25. while(System.currentTimeMillis()-now<5000l){  
  26. try{  
  27. //ThisisessentiallythebodyofEventDispatchThread  
  28. AWTEventevent=theQueue.getNextEvent();  
  29. Objectsrc=event.getSource();  
  30. if(eventinstanceofActiveEvent){  
  31. ((ActiveEvent)event).dispatch();  
  32. }elseif(srcinstanceofComponent){  
  33. ((Component)src).dispatchEvent(event);  
  34. }elseif(srcinstanceofMenuComponent){  
  35. ((MenuComponent)src).dispatchEvent(event);  
  36. }  
  37. }catch(Exceptionex){  
  38. ex.printStackTrace();  
  39. }  
  40. }  
  41. System.out.println("end");  
  42. }  
  43. });  
  44. dlg.pack();  
  45. dlg.show();  
  46. }  
  47. }  
  48.  

在上面Swing的例子中,当Button的Action被触发,actionPerformed方法执行的时候,会首先帮助EventQueue分发事件,直到最少5秒之后返回,这时可以看到这个事件处理方法至少执行了5秒钟,但是在这个过程中Dialog仍然可以正常工作,只是因为在这5秒之中并非是Sleep,而是在帮助EventQueue分发事件,如果代码改成
Thread.sleep(5000);
的话,界面将会死掉。

所以在Modal Dialog弹出的时候,实际上只要在show方法中能够实现类似上面的代码,保证事件可以正常的分发(同时截获父窗口的一些事件,过滤掉一些触发Action的事件),那么父窗口的界面就不会死掉。

当事件处理方法很长时间才能做完该怎么办

当事件处理方法需要很长时间才能执行完的话,如果需要保证界面不死的话,还是只能用多线程,虽然上面的方法实现了事件处理的时候界面不死,但是这和一般的事件处理是有不同的,上面的方法实际上在处理的时候什么都没有做,而我们一般需要有自己的操作(比如访问数据库,访问网络,读写操作等需要很长时间才能处理完的工作),不可能做到一边在操作一边处理Event分发,这个时候只有新建一个线程才是正道。

不过关于很多EventQueue in Swing和EventDispatchThread的方法都被封装在其实现里面,对外不可视,导致不可能对其进行一些修改,有点不爽。另外在EventQueue中的AWTEvent一般都是给最上层对象的,比如最上层的JDialog或者JFrame,然后由JDialog或者JFrame分发给其他的Component,不过我不知道怎么可以从AWTEvent事件找到真正的拥有者,这一点比较郁闷

【编辑推荐】

  1. 在表格中Swing增加列表框
  2. 浅谈Swing控件JList
  3. 概述Swing组件与外部线程
  4. Java Swing做什么好
  5. Swing文件选择器的制作
责任编辑:佚名 来源: 博客园
相关推荐

2009-07-14 18:28:58

Swing入门

2009-07-15 13:06:38

Swing组件

2009-07-15 14:29:24

构造JListSwing

2009-07-16 12:58:50

Swing控件

2009-07-17 12:44:01

NetBeans开发S

2009-07-10 17:20:38

Swing构件AWT构件

2009-07-10 11:07:18

Swing和SWT

2009-07-17 16:49:18

lookandfeelSwing

2009-07-15 09:59:11

Metal观感Swing

2009-07-10 13:09:53

.Net与Java S

2009-07-16 16:23:59

Swing线程

2009-07-14 14:50:00

JOptionPane

2009-07-14 17:01:29

Look&FeelSwing

2009-07-14 11:08:42

WebRendererSwing应用程序

2009-07-15 16:29:41

Swing绘画

2009-07-10 11:31:45

Swing支持透明和不规则窗口

2009-07-16 10:26:49

渲染器接口Swing

2009-07-14 17:38:20

Swing模式

2009-07-17 15:34:37

Java Swing连接数据库

2009-07-15 15:35:59

Swing程序Swing性能
点赞
收藏

51CTO技术栈公众号