Java Swing 常识篇之EDT


 Java Swing 常识篇之EDT

       从毕业到现在用SWING已经一年多,在这里想总结一下过去学到的东西和经验,和各位兄弟姐妹们一起分享。在以后的文章中也会和大家一起来分享一些好的框架。说起JAVA SWING,普遍给人的感觉是“丑、慢、难”,丑是界面丑、慢是速度慢、难是开发难。其实熟悉LAF的同学都知道SWING确实不丑;说到‘慢’,SWING也不慢,只要懂得如何处理长时间的TASK,而不是什么都在EDT处理;说到难,只要我们有一套自己专门开发SWINGUI的类库,也不难了。所以在接下来的文章中,我将会和大家构建一个SWING UI FRAMEWORK(暂时称为:Fast-DUI),在这个Fast-DUI中将会整合SWING中的动画(淡入淡出、滑上滑下)、效果(shadow、drop-shadow)、感官(LookAndFeel)等等。构建这样的一个框架主要是为了能够快速地开发出“漂亮的、用户体验好的”桌面应用程序。好了,接下来马上开始。今天的这篇文章在Swing的应用中起到举足轻重的作用。这篇文章是开头篇,可能写得不好,感觉自己的写作水平,和小学生有得一比。
        今天就一起来学习一下EDT(Event Dispatching Thread,字面上翻译成“事件分配线程”),那什么是EDT,EDT就简单地认为就是一个线程(特殊的线程),这个线程主要是管理着整个SWING GUI的事件,管理着整个UI界面(熟悉Java2D的朋友都知道,我们所看到的界面就是Java2D绘图绘出来的)。大家都知道,也许大学的时候,老师也会提到SWING不是线程安全的,不是线程安全的,那意味着我们用多线程的时候,要格外的小心,我们要把SWING里面东西的修改、获取独立放到一个线程上,但是这个刚好SWING的开发人员已经为我们解决了,我们不必自己管理一个额外的线程,我们只需要把他们放到EDT里面,下面我会举两个例子来说明一下如何使用EDT。
          第一个例子来讲一下如果不在EDT中修改Swing的东西会出现什么问题,请看下面的例子:

Java代码   收藏代码
  1. pakage org.dui.sample  
  2.   
  3. import java.awt.BorderLayout;  
  4. import javax.swing.JFrame;  
  5. import javax.swing.JTextField;  
  6. import javax.swing.SwingUtilities;  
  7.   
  8. /** 
  9.  * <code>NotInEDTSample</code> just demonstrates the usage of Swing EDT simply. 
  10.  *  
  11.  * @author Jimmy.haung(SZ Team) 
  12.  * @since <i>DUI (Mar 25, 2013)</i> 
  13.  */  
  14. public class NotInEDTSample extends JFrame {  
  15.     private static final long serialVersionUID = 1L;  
  16.     private JTextField m_txt;  
  17.   
  18.     public NotInEDTSample() {  
  19.         initGUI();  
  20.         notInEDT();  
  21.     }  
  22.   
  23.     /** 
  24.      * Init the GUI 
  25.      */  
  26.     public void initGUI() {  
  27.         this.setTitle("a simple EDT Sample");  
  28.         m_txt = new JTextField();  
  29.         getContentPane().add(m_txt, BorderLayout.CENTER);  
  30.     }  
  31.   
  32.     /** 
  33.      * Process not under the EDT. 这里我启动了10个线程来改变<code>m_txt</code>的内容. 
  34.      */  
  35.     private void notInEDT() {  
  36.         for (int i = 0; i < 4; ++i) {  
  37.             new Thread(new Runnable() {  
  38.                 @Override  
  39.                 public void run() {  
  40.                     while (true) {  
  41.                         m_txt.setText("我不在EDT中操作!");  
  42.                         try {  
  43.                             Thread.sleep(100);  
  44.                         } catch (InterruptedException e) {  
  45.                             e.printStackTrace();  
  46.                         }  
  47.                     }  
  48.                 }  
  49.             }).start();  
  50.         }  
  51.     }  
  52.   
  53.     /** 
  54.      * Launch the application. 
  55.      */  
  56.     public static void main(String[] args) {  
  57.         SwingUtilities.invokeLater(new Runnable() {  
  58.             public void run() {  
  59.                 try {  
  60.                     NotInEDTSample oFrame = new NotInEDTSample();  
  61.                     oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  62.                     oFrame.setLocationRelativeTo(null);  
  63.                     oFrame.setSize(300200);  
  64.                     oFrame.setVisible(true);  
  65.                 } catch (Exception e) {  
  66.                     e.printStackTrace();  
  67.                 }  
  68.             }  
  69.         });  
  70.     }  
  71.   
  72. }  

     运行上面的程序,然后点击几下界面后,界面就‘死掉’了(大家可以Resize看一下,或者点击一下窗口的Close按钮),‘死掉’有可能是死锁造成的,只是可能,但是程序也没有报Exception,这就是不确定性,如果Swing的stub不在EDT里面运行,带给程序很多的不确定性。在我以前看到的项目中,由于EDT的原因,引发可各种不可预测的Exception。

如果我们将上面的程序稍微改一下,将notInEDT的方法改成下面的样子:

Java代码   收藏代码
  1. private void notInEDT() {  
  2.     for (int i = 0; i < 4; ++i) {  
  3.         new Thread(new Runnable() {  
  4.             @Override  
  5.             public void run() {  
  6.                 while (true) {  
  7.                     SwingUtilities.invokeLater(new Runnable() {  
  8.                         @Override  
  9.                         public void run() {  
  10.                              m_txt.setText("我在EDT中操作!");  
  11.                         }  
  12.                     });  
  13.                       
  14.                     try {  
  15.                         Thread.sleep(100);  
  16.                     } catch (InterruptedException e) {  
  17.                         e.printStackTrace();  
  18.                     }  
  19.                 }  
  20.             }  
  21.         }).start();  
  22.     }  
  23. }  

      通过修改是不是发现没前面的问题了。但是有一些新学的朋友会问,如果本来就在EDT中就不用再加入到EDT, 但是如何才知道当前的线程是否是EDT呢,请看SwingUtilities.isEventDispatchThread();想得多周到的开发Swing的人员!SwingUtilities、SwingUtilities2、SwingUtilities3这几个类在以后都会经常用到,非常方便。看了上面的例子,大家有什么感想呢?

       下面我们接着来写一个例子,我们试想一下,如果在EDT中执行一些时间长的任务会怎样呢?

 

Java代码   收藏代码
  1. import java.awt.BorderLayout;  
  2.   
  3. /** 
  4.  * <code>NotInEDTSample</code> just demonstrates the usage of Swing EDT simply. 
  5.  *  
  6.  * @author Jimmy.haung(SZ Team) 
  7.  * @since <i>DUI (Mar 25, 2013)</i> 
  8.  */  
  9. public class LongTaskSample extends JFrame {  
  10.     private static final long serialVersionUID = 1L;  
  11.     private JButton m_btn;  
  12.   
  13.     public LongTaskSample() {  
  14.         initGUI();  
  15.         initEventHandler();  
  16.     }  
  17.   
  18.     /** 
  19.      * Init the GUI 
  20.      */  
  21.     public void initGUI() {  
  22.         this.setTitle("a simple EDT Sample");  
  23.         m_btn = new JButton("click me to process long task");  
  24.         getContentPane().add(m_btn, BorderLayout.CENTER);  
  25.     }  
  26.     /** 
  27.      * Bind the event to the component. 
  28.      */  
  29.     public void initEventHandler(){  
  30.         m_btn.addActionListener(new ActionListener() {  
  31.             @Override  
  32.             public void actionPerformed(ActionEvent e) {  
  33.                 longTask();  
  34.             }  
  35.         });  
  36.     }  
  37.   
  38.     /** 
  39.      * Use about five seconds to process this task. 
  40.      */  
  41.     private void longTask() {  
  42.         //为true,请看 #main(String[])  
  43.         System.err.println(SwingUtilities.isEventDispatchThread());  
  44.         try {  
  45.             Thread.sleep(5000);  
  46.         } catch (InterruptedException e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.     }  
  50.   
  51.     /** 
  52.      * Launch the application. 
  53.      */  
  54.     public static void main(String[] args) {  
  55.         SwingUtilities.invokeLater(new Runnable() {  
  56.             public void run() {  
  57.                 try {  
  58.                     LongTaskSample oFrame = new LongTaskSample();  
  59.                     oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  60.                     oFrame.setLocationRelativeTo(null);  
  61.                     oFrame.setSize(300200);  
  62.                     oFrame.setVisible(true);  
  63.                 } catch (Exception e) {  
  64.                     e.printStackTrace();  
  65.                 }  
  66.             }  
  67.         });  
  68.     }  
  69.   
  70. }  

        

       点击了按钮后,我们发现程序死掉了大约5秒后,就醒来了,这就是“装死”的现象。所以我们看到在EDT里面运行时间长的任务的结果会引发什么后果,就会觉得很慢。上面的两个例子只是说明了一丁点的问题。在大家以后的项目中将会遇到更多问题。那么现在的问题是如果来改善上面的问题,我们应该在其他的线程中执行时间长的任务,而在EDT只是负责界面的显示,以及界面数据的修改、获取等,这以后还会讲,在这里提示一下,SwingWorker可以很好解决上面的问题。马马虎虎终于完成了第一篇文章。如果新学的朋友,还是不懂得话,请看http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html。如果还是不明白,不要紧,以后会慢慢体会到的。前面的几篇的文章将会将一些Swing基本的东西,讲完基础的东西后将会开始我们的Fast-DUI之旅。预告一下,下一章将会是布局(Layout),如何简单使用布局管理器来实现复杂的布局。

   这里先预告一下我们以后要构建Fast-DUI的LAF(这只是其中的一种Skin,大家可以根据自己的情况来改变Skin),如下图:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值