久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Swing框架之Component:續(xù)文二

 昵稱8177340 2012-04-10

Swing框架之Component:續(xù)文二

(2007-01-10 21:36:56)
分類: Swing

         Swing的事件處理過程為:事件調(diào)度線程(Event Dispatch Thread)從事件隊列(EventQueue)中獲取底層系統(tǒng)捕獲的原生事件,,如鼠標(biāo),、鍵盤、焦點,、PAINT事件等,。接著調(diào)用該事件源組件的dispachEvent,。該方法過濾出特殊事件后,調(diào)用processEvent進(jìn)行處理,。processEvent方法根據(jù)事件類型調(diào)用注冊在這個組件上的相應(yīng)事件處理器函數(shù),。事件處理器函數(shù)根據(jù)這些事件的特征,判斷出用戶的期望行為,,然后根據(jù)期望行為改變組件的狀態(tài),,然后根據(jù)需要刷新組件外觀,觸發(fā)帶有特定語義的高級事件,。此事件繼續(xù)傳播下去,,直至調(diào)用應(yīng)用程序注冊在該組件上的處理器函數(shù)。下圖是這個過程的示意圖:

  Swing框架之Component:續(xù)文二

         上圖所示意的過程簡要說就是:

Pump an Event->Dispatch & Process Event->MouseListener.mousePressed->fireActionPerformed->ActionListener.actionPeformed->Do database query and display result to a table->Return from actionPerformed->Return from fireActionPerformed->Return from MouseListener.mousePressed->Pump another Event.

         事件調(diào)度線程在應(yīng)用程序事件處理函數(shù)actionPerformed沒有完成之前是不能處理下一個事件的,,如果應(yīng)用程序處理函數(shù)是一個時間復(fù)雜的任務(wù)(比如查詢數(shù)據(jù)庫并將結(jié)果顯示到表格中),,后面包括PAINT事件將在長時間內(nèi)得不到執(zhí)行。由于PAINT事件負(fù)責(zé)將界面更新,,所以這就使用戶界面失去響應(yīng),。

          打一個比方,事件處理線程就像進(jìn)入某城唯一的單行道一樣,,事件相當(dāng)于汽車,。有種PAINT汽車負(fù)責(zé)為城市運輸非常重要的生活物資。但是有一天,,PAINT前面有一輛汽車突然壞掉了,,司機(jī)下來修車。但是這車太難修,,一修就是幾天,,結(jié)果后面的PAINT汽車無法前進(jìn),物資無法按時運到城里,。市民急了,,市長雖然不停的打電話催PAINT公司,但即使PAINT公司多添加幾輛車也沒用,。由于進(jìn)城的唯一條路被那輛車給占著,,所以再多的PAINT車也只能堵在路上。

         不了解Swing的這種事件處理模型的人往往將時間復(fù)雜的任務(wù)放在處理函數(shù)中完成,,這是造成Swing應(yīng)用程序速度很慢的原因,。用戶觸發(fā)這個動作,用戶界面就失去了響應(yīng),,于是給用戶的感覺就是Swing太慢了,。其實這個錯誤是程序員造成的,并不是Swing的過失。

         說點題外話,,所有采用這種事件模型的用戶界面工具都會產(chǎn)生這種問題,,包括SWT、GTK,、MFC等流行的用戶界面工具,。之所以只有Swing被誤解,主要是和Swing的歷史,、市場時機(jī),、商業(yè)宣傳策略和心理學(xué)相關(guān)的。

         首先Swing的歷史和市場時機(jī)極差,。Swing出現(xiàn)早期性能也差,、錯誤也多,而Java程序員脫身于傳統(tǒng)圖形界面工具,,對于Swing這種新的事件處理模型并不太了解,,而此時正處于Java第一輪狂熱的時期,大家都滿懷希望做了大量的Swing應(yīng)用程序,,而這些程序中大量存在這種錯誤方法,。于是市場上涌現(xiàn)了大批的這種程序。自從那個時代,,因為這些程序,,Swing被貼上了慢的標(biāo)簽。又由于當(dāng)時的Swing界面也丑,,和一般的Windows程序風(fēng)格炯異,更加深人們的這種印象,。這種印象一直持續(xù)到現(xiàn)在,,像烙印一樣深深的刻在人們的腦海里。

           其次,,Swing還有一個致命的問題,,就是沒有涌現(xiàn)出一個具有標(biāo)識性的好程序,這是造成它比SWT印象慘的原因,。為什么SWT采用相同的事件處理模型,,而獲得了速度快的聲譽呢?這是因為人們當(dāng)時對于Java做桌面應(yīng)用的期望心理達(dá)到了低谷,,而SWT的出現(xiàn)恰恰是伴隨Eclipse出現(xiàn)的,,早期的Eclipse的確是在速度快、界面漂亮,,這一掃當(dāng)時人們認(rèn)為Java慢,,Java界面丑陋,Java無法做桌面應(yīng)用的印象,,繼而這個印象被加在SWT身上,,人們認(rèn)為Eclipse速度快,、漂亮是因為SWT,其實如果你知道Swing/SWT事件處理模型的話,,你就明白功勞是Eclipse開發(fā)者的,,Eclipse界面漂亮其實要歸功于Eclipse界面設(shè)計專家,他們的高水平造就了這個好的IDE,,從而也抬起了SWT的聲譽,。而Swing的名譽恰恰就被早期Swing低水平開發(fā)者給毀了。

        再次, 這和商業(yè)宣傳策略有關(guān),。IBM和Eclipse很懂得市場宣傳,,人們不是認(rèn)為Java慢嗎,就宣傳SWT使用原生組件,,人們不是認(rèn)為Swing丑陋,、風(fēng)格炯異吧,就宣傳SWT風(fēng)格一致性,,人們不是認(rèn)為Java不能做桌面應(yīng)用嗎,,就宣傳基于SWT的Eclipse。其實這一切的背后原因只是“人”的不同,,Eclipse的開發(fā)者和Swing應(yīng)用程序的開發(fā)者,,Swing和SWT技術(shù)差異并沒有造成那么大的差別,如果是相近能力的人使用他們開發(fā)的話,,應(yīng)該能做出相近的產(chǎn)品,。這可以從現(xiàn)在Eclipse和NetBeans、Intellij IDEA,、JDeveloper和JBuilder看的出來,。

         最后,人類有一個心理學(xué)現(xiàn)象,,就是一旦形成對某種事物的印象,,很難擺脫舊的認(rèn)識,有時甚至人們不愿意承認(rèn)擺在眼前的事實,??偠灾琒wing和SWT不同遭遇是因為歷史,、市場時機(jī),、商業(yè)宣傳策略、心理學(xué)的種種原因造成的,。

          那么如何避免這個問題,,編寫響應(yīng)速度快的Swing應(yīng)用程序呢?在SwingWorker的javadoc中有這樣兩條原則:

Time-consuming tasks should not be run on the Event Dispatch Thread. Otherwise the application becomes unresponsive. 耗時任務(wù)不要放到事件調(diào)度線程上執(zhí)行,否則程序就會失去響應(yīng),。

Swing components should be accessed on the Event Dispatch Thread only. Swing組件只能在事件調(diào)度線程上訪問,。

         因此處理耗時任務(wù)時,首先要啟動一個專門線程,,將當(dāng)前任務(wù)交給這個線程處理,,而當(dāng)前處理函數(shù)立即返回,繼續(xù)處理后面未決的事件,。這就像前面塞車的例子似的,,那個司機(jī)只要簡單的把車開到路邊或者人行道上修理,整個公路系統(tǒng)就會恢復(fù)運轉(zhuǎn),。

         其次,,在為耗時任務(wù)啟動的線程訪問Swing組件時,要使用SwingUtilties. invokeLater或者SwingUtilities.invokeAndWait來訪問,,invokeLater和invokeAndWait的參數(shù)都是一個Runnable對象,,這個Runnable對象將被像普通事件處理函數(shù)一樣在事件調(diào)度線程上執(zhí)行。這兩個函數(shù)的區(qū)別是,,invokeLater不阻塞當(dāng)前任務(wù)線程,,invokeAndWait阻塞當(dāng)前線程,直到Runnable對象被執(zhí)行返回才繼續(xù),。在前面塞車的例子中,,司機(jī)在路邊修車解決了塞車問題,但是他突然想起來要家里辦些事情,,這時他就可以打個電話讓家里開車來,。假如修車不受這件事情的影響,比如叫家人送他朋友一本書,,他可以繼續(xù)修車,,這時就相當(dāng)于invokeLater;假如修車受影響,,比如缺少某個汽車零件,叫家人給他送過來,,那么在家人來之前,,他就沒法繼續(xù)修車,這時就相當(dāng)于invokeAndWait,。

         下面舉一個例子說明這兩點,,比如按下查詢按鈕,查詢數(shù)據(jù)量很大的數(shù)據(jù)庫,,并顯示在一個表中,,這個過程需要給用戶一個進(jìn)度提示,并且能動態(tài)顯示表格數(shù)據(jù)動態(tài)增加的過程。假設(shè)按鈕的處理函數(shù)是myButton_actionPerformed,,則:

void myButton_actionPerformed(ActionEvent evt){
     new MyQueryTask().start();
}
public class MyQueryTask extends Thread{
    public void run(){
        //查詢數(shù)據(jù)庫
        final ResultSet result=...;
       / /顯示記錄
      for(;result.next();){
          //往表的Model中添加一行數(shù)據(jù),,并更新進(jìn)度條,注意這都是訪問組件
         SwingUtilities.invokeLater(new Runnable(){
              public void run(){
                    addRecord(result);
              }
         });
      }
   ....
   }
   void addRecord(ResultSet result){
       //往表格中添加數(shù)據(jù)
       jTable.add....
      //更新進(jìn)度條
      jProgress.setValue(....);
    }
}

         JDK1.6以后,,Swing提供了一個專門的類SwingWorker能幫你解決這個編程范式,,你所需要做的就是繼承這個類,重載doInBackground,,然后在actionPeformed中調(diào)用它的execute方法,,并通過publish/process方法來更新界面。SwingWorker的主要方法和它們的作用在下面的示意圖:

Swing框架之Component:續(xù)文二

          從上面示意圖可以看出,,SwingWorker實際上不過是封裝了前面我所說的例子中的MyQueryTask,,并做了更詳盡的考慮。execute方法相當(dāng)于MyQueryTask線程start,,它啟動這個后臺線程并立刻返回,。SwingWorker可以注冊PropertyChangeListener,這些listener都被在事件調(diào)度線程上執(zhí)行,,相當(dāng)于MyQueryTask中的那些訪問組件的Runnable對象,。另外,publish,、setProgress只不過是特殊的property事件吧,,process和done不過是響應(yīng)publish和PropertyChangeEvent.DONE這個事件的方法罷了。因此我們很容易將上面的例子改成SwingWorker的版本:

void myButton_actionPerformed(ActionEvent evt){
    new MyQueryTask().execute();
}

public class MyQueryTask extends SwingWorker{
    public void doInBackground(){
        //查詢數(shù)據(jù)庫
        final ResultSet result=...;
        //顯示記錄
        for(;result.next();){
            //往表的Model中添加一行數(shù)據(jù),,并更新進(jìn)度條,,注意這都是訪問組件
            publish(result);
        }
        ....
    }
    public void process(Object ... result){
        //往表格中添加數(shù)據(jù)
        jTable.add....
        //更新進(jìn)度條
        jProgress.setValue(....);
    }
}

         對于一般的耗時任務(wù)這樣做是比較普遍的,但是有一些任務(wù)是一旦觸發(fā)之后,,會周期性的觸發(fā),,如何做處理這種任務(wù)呢?JDK中提供了兩個Timer類幫你完成定時任務(wù),一個是javax.swing.Timer,,一個java.util.Timer,。使用它們的方法很簡單,對于Swing的timer,,使用方法如下:

public void myActionPerformed(){
    //假設(shè)點擊了某個按鈕開始記時
    Action myAction=new AbstractAction(){
        public void actionPerformed(ActionEvent e){
            //做周期性的活動,,比如顯示當(dāng)前時間
            Date date=new Date();
            jMyDate.setDate(date);//jMyDate是個假想的組件,能顯示日期時間
        }
    };
    new Timer(1000, myAction).start();
}

         java.util.Timer類似,,只不過使用TimerTask完成動作封裝,。注意這兩個Timer有一個關(guān)鍵的區(qū)別:Swing的Timer的事件處理都是在事件調(diào)度線程上進(jìn)行的,因而它里面的操作可以直接訪問Swing組件,。而java.util.Timer則可能在其他線程上,,因而訪問組件時要使用SwingUtilities.invokeLater和invokeAndWait來進(jìn)行,。這一點要記住。

         如果要了解更詳細(xì)的信息,,可以查閱SwingWorker,、Swing Timer和util Timer這些類javadoc文檔和其他網(wǎng)上資料。最重要的是要記住了那兩條原則,。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多