Swing


          天行健 君子以自強(qiáng)不息

          posts - 69, comments - 215, trackbacks - 0, articles - 16
             :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          SwingUtilities中invokeLater和invokeAndWait的介紹

          Posted on 2007-07-10 14:28 zht 閱讀(12610) 評論(0)  編輯  收藏 所屬分類: Swing

          SwingUtilities中invokeLater和invokeAndWait介紹
             在Java中Swing是線程不安全的,是單線程的設(shè)計,這樣的造成結(jié)果就是:只能從事件派發(fā)線程訪問將要在屏幕上繪制的Swing組件。事件派發(fā)線程是調(diào)用paint和update等回調(diào)方法的線程,它還是事件監(jiān)聽器接口中定義的事件處理方法,例如,ActionListener中的actionPerformed方法在事件派發(fā)線程中調(diào)用。
             Swing是事件驅(qū)動的,所以在回調(diào)函數(shù)中更新可見的GUI是很自然的事情,比如,有一個按鈕被按下,項目列表需要更新時,則通常在與該按鈕相關(guān)聯(lián)的事件監(jiān)聽器的actionPerformed方法中來實(shí)現(xiàn)該列表的更新,從事件派發(fā)線程以外的線程中更新Swing組件是不正常的。
             有時需要從事件派發(fā)線程以外的線程中更新Swing組件,例如,在actionPerformed中有很費(fèi)時的操作,需要很長時間才能返回,按鈕激活后需要很長時間才能看到更新的列表,按鈕會長時間保持按下的狀態(tài)只到actionPerformed返回,一般說來耗時的操作不應(yīng)該在事件處理方法中執(zhí)行,因為事件處理返回之前,其他事件是不能觸發(fā)的,界面類似于卡住的狀況,所以在獨(dú)立的線程上執(zhí)行比較耗時的操作可能更好,這會立即更新用戶界面和釋放事件派發(fā)線程去派發(fā)其他的事件。
             SwingUtilities類提供了兩個方法:invokeLate和invoteAndWait,它們都使事件派發(fā)線程上的可運(yùn)行對象排隊。當(dāng)可運(yùn)行對象排在事件派發(fā)隊列的隊首時,就調(diào)用其run方法。其效果是允許事件派發(fā)線程調(diào)用另一個線程中的任意一個代碼塊。
             只有從事件派發(fā)線程才能更新組件。
             程序示例:更新組件的錯誤方法
             startButton.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
              GetInfoThread t = new GetInfoThread(Test.this);
              t.start();
              startButton.setEnabled(false);
             }
            });
            
            class GetInfoThread extends Thread {
           Test applet;

           public GetInfoThread(Test applet) {
            this.applet = applet;
           }

            public void run() {
             while (true) {
              try {
               Thread.sleep(500);
               applet.getProgressBar().setValue(Math.random() * 100);
              } catch (InterruptedException e) {
               e.printStackTrace();
              }
             }
            }
           }
           錯誤分析:在actionPerformed中,監(jiān)聽器把按鈕的允許狀態(tài)設(shè)置為false,由于是在事件派發(fā)線程上調(diào)用actionPerformed,所以setEnabled是一個有效的操作,但是在GetInfoThread中設(shè)置進(jìn)度條是一個危險的做法,因為事件派發(fā)線程以外的線程更新了進(jìn)度條,所以運(yùn)行是不正常的。

             1、invokeLater使用
              class GetInfoThread extends Thread {
            Test applet;
           
            Runnable runx;
           
            int value;

            public GetInfoThread(final Test applet) {
             this.applet = applet;
             runx = new Runnable() {
              public void run() {
               JProgressBar jpb = applet.getProgressBar();
               jpb.setValue(value);
              }
             };
            }

             public void run() {
              while (true) {
               try {
                Thread.sleep(500);
                value = (int) (Math.random() * 100);
                System.out.println(value);
                SwingUtilities.invokeLater(runx);
               } catch (InterruptedException e) {
                e.printStackTrace();
               }
              }
             }
            }
             
             2、invokeAndWait
             與invoikeLater一樣,invokeAndWait也把可運(yùn)行對象排入事件派發(fā)線程的隊列中,invokeLater在把可運(yùn)行的對象放入隊列后就返回,而invokeAndWait一直等待知道已啟動了可運(yùn)行的run方法才返回。如果一個操作在另外一個操作執(zhí)行之前必須從一個組件獲得信息,則invokeAndWait方法是很有用的。
             class GetInfoThread extends Thread {
             Runnable getValue,setValue;
             int value,currentValue;
             public GetInfoThread(final Test applet){
             getValue=new Runnable(){
             public void run(){
              JProgressBar pb=applet.getProgressBar();
              currentValue=pb.getValue();
              }
             };
             setValue=new Runnable(){
              public void run(){
               JProgressBar pb=applet.getProgressBar();
               pb.setValue(value);
              }
             }
             }
             public void run(){
              while(true){
              try{
              Thread.currentThead().sleep(500);
              value=(int)(Math.random()*100);
              try{
              SwingUtilities.invokeAndWait(getValue);//直到getValue可運(yùn)行的run方法返回后才返回
                }catch(Exception ex){
                }
                if(currentValue!=value){
                SwingUtilities.invokeLater(setValue);
                }
               }
               }catch(Exception ex){
                }
              }
             }
             invokeLater和invoikeAndWait的一個重要區(qū)別:可以從事件派發(fā)線程中調(diào)用invokeLater,卻不能從事件派發(fā)線程中調(diào)用invokeAndWait,從事件派發(fā)線程調(diào)用invokeAndWait的問題是:invokeAndWait鎖定調(diào)用它的線程,直到可運(yùn)行對象從事件派發(fā)線程中派發(fā)出去并且該可運(yùn)行的對象的run方法激活,如果從事件派發(fā)線程調(diào)用invoikeAndWait,則會發(fā)生死鎖的狀況,因為invokeAndWait正在等待事件派發(fā),但是,由于是從事件派發(fā)線程中調(diào)用invokeAndWait,所以直到invokeAndWait返回后事件才能派發(fā)。
             ex)actionPerformed();返回的時候事件派發(fā)線程才能派發(fā)線程,而在actionPerformed中使用invokeAndWait則會導(dǎo)致actionPerformed不能返回。所以也就無法派發(fā)invokeAndWait中的線程。

          由于Swing是線程不安全的,所以,從事件派發(fā)線程之外的線程訪問Swing組件是不安全的,SwingUtilities類提供這兩種方法用于執(zhí)行事件派發(fā)線程中的代碼

          主站蜘蛛池模板: 马龙县| 大兴区| 达拉特旗| 长葛市| 孝昌县| 林州市| 江川县| 浠水县| 阜康市| 比如县| 湖南省| 德惠市| 重庆市| 田东县| 麻阳| 商城县| 清丰县| 长宁县| 凌海市| 梅河口市| 田阳县| 从化市| 乐业县| 皮山县| 安徽省| 同江市| 康保县| 吉木乃县| 尼勒克县| 阿瓦提县| 精河县| 襄樊市| 平山县| 台中县| 玛沁县| 崇左市| 西贡区| 金乡县| 绥德县| 仪征市| 怀化市|