java something

          不要以為......很遙遠(yuǎn)
          隨筆 - 23, 文章 - 1, 評論 - 2, 引用 - 0
          數(shù)據(jù)加載中……

          2011年2月17日

          Activity生命周期

          現(xiàn)有兩個Activity:  Activity1,Activity2

          先啟動Activity1運(yùn)行順序?yàn)椋?Activity1 onCreate -> Activity1 onStart -> Activity1 onResume
          用Intent從Activity1跳到Activity2運(yùn)行順序 : 
          Activity1 onPause -> Activity2 onCreate -> Activity2 onStart -> Activity2 onResume ->Activity1 onStop -> Activity1  onDestroy
          退出應(yīng)用程序: Activity2 onResume ->Activity2 onStop -> Activity2  onDestroy

          posted @ 2011-09-02 17:48 Jamie 閱讀(229) | 評論 (0)編輯 收藏

          控制3個線程運(yùn)行順序的Demo

          本程序可以控制3個線程按順序執(zhí)行, 代碼如下:

          public class Test3 {

           public static void main(String[] args) throws IOException {
            final Test obj = new Test();
            
            new Thread()
            {
             public void run()
             {
              obj.m1();
             }
            }.start();
            new Thread()
            {
             public void run()
             {
              obj.m2();
             }
            }.start();
            new Thread()
            {
             public void run()
             {
              obj.m3();
             }
            }.start();
            
           }

          }

          class Test
          {
           static int count;
           volatile int target = 1;
           synchronized void m1()
           { 
             for (int i = 0; i < 10; i++)
             {
              while (target == 2 || target == 3)
              {
               try {
                wait();
               } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
               }
              }
              System.out.println("m1() =" + i);
              target = 2;
              notifyAll();
             }
           }
           
           synchronized void m2()
           {
            for (int i = 0; i < 10; i++)
            {
             while (target == 1 || target == 3)
             {
              try {
               wait();
              } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
              }
             }
             System.out.println("m2() =" + i);
             target = 3;
             notifyAll();
            }
           }
           
           synchronized void m3()
           {
            for (int i = 0; i < 10; i++)
            {
             while (target == 1 || target == 2)
             {
              try {
               wait();
              } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
              }
             }
             System.out.println("m3() =" + i);
             target = 1;
             notifyAll();
            }
           }
          }

          posted @ 2011-09-02 02:27 Jamie 閱讀(1778) | 評論 (2)編輯 收藏

          線程的同步與共享

               摘要: 線程的同步與共享 前面程序中的線程都是獨(dú)立的、異步執(zhí)行的線程。但在很多情況下,多個線程需要共享數(shù)據(jù)資源,這就涉及到線程的同步與資源共享的問題。 1 資源沖突 下面的例子說明,多個線程共享資源,如果不加以控制可能會產(chǎn)生沖突。 程序CounterTest.java   Code highlighting produced by Actipro CodeHighlight...  閱讀全文

          posted @ 2011-09-02 01:38 Jamie 閱讀(485) | 評論 (0)編輯 收藏

          線程的狀態(tài)與調(diào)度

            1,線程的生命周期

                  線程從創(chuàng)建、運(yùn)行到結(jié)束總是處于下面五個狀態(tài)之一:新建狀態(tài)、就緒狀態(tài)、運(yùn)行狀態(tài)、阻塞狀態(tài)及死亡狀態(tài)。



              1.新建狀態(tài)(New): 
                  當(dāng)用new操作符創(chuàng)建一個線程時, 例如new Thread(r),線程還沒有開始運(yùn)行,此時線程處在新建狀態(tài)。 當(dāng)一個線程處于新生狀態(tài)時,程序還沒有開始運(yùn)行線程中的代碼

               2.就緒狀態(tài)(Runnable)

                  一個新創(chuàng)建的線程并不自動開始運(yùn)行,要執(zhí)行線程,必須調(diào)用線程的start()方法。當(dāng)線程對象調(diào)用start()方法即啟動了線程,start()方法創(chuàng)建線程運(yùn)行的系統(tǒng)資源,并調(diào)度線程運(yùn)行run()方法。當(dāng)start()方法返回后,線程就處于就緒狀態(tài)。

                  處于就緒狀態(tài)的線程并不一定立即運(yùn)行run()方法,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間才可以運(yùn)行線程。因?yàn)樵趩?/span>CPU的計(jì)算機(jī)系統(tǒng)中,不可能同時運(yùn)行多個線程,一個時刻僅有一個線程處于運(yùn)行狀態(tài)。因此此時可能有多個線程處于就緒狀態(tài)。對多個處于就緒狀態(tài)的線程是由Java運(yùn)行時系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。

              3.運(yùn)行狀態(tài)(Running)

                  當(dāng)線程獲得CPU時間后,它才進(jìn)入運(yùn)行狀態(tài),真正開始執(zhí)行run()方法.

              
          4. 阻塞狀態(tài)(Blocked)

                  線程運(yùn)行過程中,可能由于各種原因進(jìn)入阻塞狀態(tài):
                  1>線程通過調(diào)用sleep方法進(jìn)入睡眠狀態(tài);
                  2>線程調(diào)用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調(diào)用者;
                  3>線程試圖得到一個鎖,而該鎖正被其他線程持有;
                  4>線程在等待某個觸發(fā)條件;
                  ......           

                  所謂阻塞狀態(tài)是正在運(yùn)行的線程沒有運(yùn)行結(jié)束,暫時讓出
          CPU,這時其他處于就緒狀態(tài)的線程就可以獲得CPU時間,進(jìn)入運(yùn)行狀態(tài)。

              5. 死亡狀態(tài)(Dead)

                  有兩個原因會導(dǎo)致線程死亡:
                  1) run方法正常退出而自然死亡,
                  2) 一個未捕獲的異常終止了run方法而使線程猝死。
                  為了確定線程在當(dāng)前是否存活著(就是要么是可運(yùn)行的,要么是被阻塞了),需要使用isAlive方法。如果是可運(yùn)行或被阻塞,這個方法返回true; 如果線程仍舊是new狀態(tài)且不是可運(yùn)行的, 或者線程死亡了,則返回false.




          2,  線程的優(yōu)先級和調(diào)度

          Java的每個線程都有一個優(yōu)先級,當(dāng)有多個線程處于就緒狀態(tài)時,線程調(diào)度程序根據(jù)線程的優(yōu)先級調(diào)度線程運(yùn)行。

          可以用下面方法設(shè)置和返回線程的優(yōu)先級。

              · public final void setPriority(int newPriority) 設(shè)置線程的優(yōu)先級。

              · public final int getPriority() 返回線程的優(yōu)先級。

          newPriority為線程的優(yōu)先級,其取值為110之間的整數(shù),也可以使用Thread類定義的常量來設(shè)置線程的優(yōu)先級,這些常量分別為:Thread.MIN_PRIORITY、Thread.NORM_PRIORITY、Thread.MAX_PRIORITY,它們分別對應(yīng)于線程優(yōu)先級的1510,數(shù)值越大優(yōu)先級越高。當(dāng)創(chuàng)建Java線程時,如果沒有指定它的優(yōu)先級,則它從創(chuàng)建該線程那里繼承優(yōu)先級。

          一般來說,只有在當(dāng)前線程停止或由于某種原因被阻塞,較低優(yōu)先級的線程才有機(jī)會運(yùn)行。

          前面說過多個線程可并發(fā)運(yùn)行,然而實(shí)際上并不總是這樣。由于很多計(jì)算機(jī)都是單CPU的,所以一個時刻只能有一個線程運(yùn)行,多個線程的并發(fā)運(yùn)行只是幻覺。在單CPU機(jī)器上多個線程的執(zhí)行是按照某種順序執(zhí)行的,這稱為線程的調(diào)度(scheduling)。

          大多數(shù)計(jì)算機(jī)僅有一個CPU,所以線程必須與其他線程共享CPU。多個線程在單個CPU是按照某種順序執(zhí)行的。實(shí)際的調(diào)度策略隨系統(tǒng)的不同而不同,通常線程調(diào)度可以采用兩種策略調(diào)度處于就緒狀態(tài)的線程。

          (1) 搶占式調(diào)度策略

               Java運(yùn)行時系統(tǒng)的線程調(diào)度算法是搶占式的 (preemptive)。Java運(yùn)行時系統(tǒng)支持一種簡單的固定優(yōu)先級的調(diào)度算法。如果一個優(yōu)先級比其他任何處于可運(yùn)行狀態(tài)的線程都高的線程進(jìn)入就緒狀態(tài),那么運(yùn)行時系統(tǒng)就會選擇該線程運(yùn)行。新的優(yōu)先級較高的線程搶占(preempt)了其他線程。但是Java運(yùn)行時系統(tǒng)并不搶占同優(yōu)先級的線程。換句話說,Java運(yùn)行時系統(tǒng)不是分時的(time-slice)。然而,基于Java Thread類的實(shí)現(xiàn)系統(tǒng)可能是支持分時的,因此編寫代碼時不要依賴分時。當(dāng)系統(tǒng)中的處于就緒狀態(tài)的線程都具有相同優(yōu)先級時,線程調(diào)度程序采用一種簡單的、非搶占式的輪轉(zhuǎn)的調(diào)度順序。

          (2) 時間片輪轉(zhuǎn)調(diào)度策略

              有些系統(tǒng)的線程調(diào)度采用時間片輪轉(zhuǎn)(round-robin)調(diào)度策略。這種調(diào)度策略是從所有處于就緒狀態(tài)的線程中選擇優(yōu)先級最高的線程分配一定的CPU時間運(yùn)行。該時間過后再選擇其他線程運(yùn)行。只有當(dāng)線程運(yùn)行結(jié)束、放棄(yield)CPU或由于某種原因進(jìn)入阻塞狀態(tài),低優(yōu)先級的線程才有機(jī)會執(zhí)行。如果有兩個優(yōu)先級相同的線程都在等待CPU,則調(diào)度程序以輪轉(zhuǎn)的方式選擇運(yùn)行的線程。

           3.  線程狀態(tài)的改變

          一個線程在其生命周期中可以從一種狀態(tài)改變到另一種狀態(tài),線程狀態(tài)的變遷如圖所示:

              
              
          1>  控制線程的啟動和結(jié)束

          當(dāng)一個新建的線程調(diào)用它的start()方法后即進(jìn)入就緒狀態(tài),處于就緒狀態(tài)的線程被線程調(diào)度程序選中就可以獲得CPU時間,進(jìn)入運(yùn)行狀態(tài),該線程就開始運(yùn)行run()方法。

          控制線程的結(jié)束稍微復(fù)雜一點(diǎn)。如果線程的run()方法是一個確定次數(shù)的循環(huán),則循環(huán)結(jié)束后,線程運(yùn)行就結(jié)束了,線程對象即進(jìn)入死亡狀態(tài)。如果run()方法是一個不確定循環(huán),早期的方法是調(diào)用線程對象的stop()方法,然而由于該方法可能導(dǎo)致線程死鎖,因此從1.1版開始,不推薦使用該方法結(jié)束線程。一般是通過設(shè)置一個標(biāo)志變量,在程序中改變標(biāo)志變量的值實(shí)現(xiàn)結(jié)束線程。請看下面的例子:

          程序 ThreadStop.java

          import java.util.*;

          class Timer implements Runnable{

              
          boolean flag=true;
              
          public void run(){
                
          while(flag){
                  System.out.print(
          "\r\t"+new Date()+"");
                  
          try{
                        Thread.sleep(
          1000);
                  }
          catch(InterruptedException e){} 
                }
                System.out.println(
          "\n"+Thread.currentThread().getName()+" Stop");
              }

              
          public void stopRun(){
                     flag 
          = false;
              }
          }

          public class ThreadStop{
              
          public static void main(String args[]){
                 Timer timer 
          = new Timer();
                 Thread thread 
          = new Thread(timer);       
                 thread.setName(
          "Timer");
                 thread.start();

                 
          for(int i=0;i<100;i++){
                   System.out.print(
          "\r"+i);
                  
          try{
                        Thread.sleep(
          100);
                  }
          catch(InterruptedException e){} 
                 }     
                 timer.stopRun();
              }
          }

          該程序在Timer類中定義了一個布爾變量flag,同時定義了一個stopRun()方法,在其中將該變量設(shè)置為false。在主程序中通過調(diào)用該方法,從而改變該變量的值,使得run()方法的while循環(huán)條件不滿足,從而實(shí)現(xiàn)結(jié)束線程的運(yùn)行。

          說明  Thread類中除了stop()方法被標(biāo)注為不推薦(deprecated) 使用外,suspend()方法和resume()方法也被標(biāo)明不推薦使用,這兩個方法原來用作線程的掛起和恢復(fù).

          2>  線程阻塞條件

          處于運(yùn)行狀態(tài)的線程除了可以進(jìn)入死亡狀態(tài)外,還可能進(jìn)入就緒狀態(tài)和阻塞狀態(tài)。下面分別討論這兩種情況:

          (1) 運(yùn)行狀態(tài)到就緒狀態(tài)

          處于運(yùn)行狀態(tài)的線程如果調(diào)用了yield()方法,那么它將放棄CPU時間,使當(dāng)前正在運(yùn)行的線程進(jìn)入就緒狀態(tài)。這時有幾種可能的情況:如果沒有其他的線程處于就緒狀態(tài)等待運(yùn)行,該線程會立即繼續(xù)運(yùn)行;如果有等待的線程,此時線程回到就緒狀態(tài)狀態(tài)與其他線程競爭CPU時間,當(dāng)有比該線程優(yōu)先級高的線程時,高優(yōu)先級的線程進(jìn)入運(yùn)行狀態(tài),當(dāng)沒有比該線程優(yōu)先級高的線程時,但有同優(yōu)先級的線程,則由線程調(diào)度程序來決定哪個線程進(jìn)入運(yùn)行狀態(tài),因此線程調(diào)用yield()方法只能將CPU時間讓給具有同優(yōu)先級的或高優(yōu)先級的線程而不能讓給低優(yōu)先級的線程。

          一般來說,在調(diào)用線程的yield()方法可以使耗時的線程暫停執(zhí)行一段時間,使其他線程有執(zhí)行的機(jī)會。

          (2) 運(yùn)行狀態(tài)到阻塞狀態(tài)

          有多種原因可使當(dāng)前運(yùn)行的線程進(jìn)入阻塞狀態(tài),進(jìn)入阻塞狀態(tài)的線程當(dāng)相應(yīng)的事件結(jié)束或條件滿足時進(jìn)入就緒狀態(tài)。使線程進(jìn)入阻塞狀態(tài)可能有多種原因:

          線程調(diào)用了sleep()方法,線程進(jìn)入睡眠狀態(tài),此時該線程停止執(zhí)行一段時間。當(dāng)時間到時該線程回到就緒狀態(tài),與其他線程競爭CPU時間。

          Thread類中定義了一個interrupt()方法。一個處于睡眠中的線程若調(diào)用了interrupt()方法,該線程立即結(jié)束睡眠進(jìn)入就緒狀態(tài)。

          如果一個線程的運(yùn)行需要進(jìn)行I/O操作,比如從鍵盤接收數(shù)據(jù),這時程序可能需要等待用戶的輸入,這時如果該線程一直占用CPU,其他線程就得不到運(yùn)行。這種情況稱為I/O阻塞。這時該線程就會離開運(yùn)行狀態(tài)而進(jìn)入阻塞狀態(tài)。Java語言的所有I/O方法都具有這種行為。

          ③ 有時要求當(dāng)前線程的執(zhí)行在另一個線程執(zhí)行結(jié)束后再繼續(xù)執(zhí)行,這時可以調(diào)用join()方法實(shí)現(xiàn),join()方法有下面三種格式:

          ·         public void join() throws InterruptedException 使當(dāng)前線程暫停執(zhí)行,等待調(diào)用該方法的線程結(jié)束后再執(zhí)行當(dāng)前線程。

          ·         public void join(long millis) throws InterruptedException 最多等待millis毫秒后,當(dāng)前線程繼續(xù)執(zhí)行。

          ·         public void join(long millis, int nanos) throws InterruptedException 可以指定多少毫秒、多少納秒后繼續(xù)執(zhí)行當(dāng)前線程。

          上述方法使當(dāng)前線程暫停執(zhí)行,進(jìn)入阻塞狀態(tài),當(dāng)調(diào)用線程結(jié)束或指定的時間過后,當(dāng)前線程線程進(jìn)入就緒狀態(tài),例如執(zhí)行下面代碼:

          t.join();

          將使當(dāng)前線程進(jìn)入阻塞狀態(tài),當(dāng)線程t執(zhí)行結(jié)束后,當(dāng)前線程才能繼續(xù)執(zhí)行。

          ④ 線程調(diào)用了wait()方法,等待某個條件變量,此時該線程進(jìn)入阻塞狀態(tài)。直到被通知(調(diào)用了notify()notifyAll()方法)結(jié)束等待后,線程回到就緒狀態(tài)。

          另外如果線程不能獲得對象鎖,也進(jìn)入就緒狀態(tài)。

          后兩種情況在下一節(jié)討論。



















          posted @ 2011-09-01 21:43 Jamie 閱讀(4010) | 評論 (0)編輯 收藏

          復(fù)習(xí)下java多線程

          好久沒搞這個了,今天把以前的筆記整理下,當(dāng)復(fù)習(xí)。

          Thread類和Runnable接口

          多線程是一個程序中可以有多段代碼同時運(yùn)行,那么這些代碼寫在哪里,如何創(chuàng)建線程對象呢?

              首先,我們來看Java語言實(shí)現(xiàn)多線程編程的類和接口。在java.lang包中定義了Runnable接口和Thread類。

           

          Runnable接口中只定義了一個方法:

          ·         public abstract void run()

          這個方法要由實(shí)現(xiàn)了Runnable接口的類實(shí)現(xiàn)。Runnable對象稱為可運(yùn)行對象,一個線程的運(yùn)行就是執(zhí)行該對象的run()方法。


                Thread
          類實(shí)現(xiàn)了Runnable接口,因此Thread對象也是可運(yùn)行對象。同時Thread類也是線程類,該類的常用構(gòu)造方法如下:

          ·         public Thread()

          ·         public Thread(Runnable target)

          ·         public Thread(String name)

          ·         public Thread(Runnable target, String name)
          target為線程運(yùn)行的目標(biāo)對象,即線程調(diào)用start()方法啟動后運(yùn)行那個對象的run()方法,該對象的類型為Runnable,若沒有指定目標(biāo)對象,則以當(dāng)前類對象為目標(biāo)對象,name為線程名


           

            線程的創(chuàng)建 

          介紹下如何創(chuàng)建和運(yùn)行線程的兩種方法。線程運(yùn)行的代碼就是實(shí)現(xiàn)了Runnable接口的類的run()方法或者是Thread類的子類的run()方法,因此構(gòu)造線程體就有兩種方法:
              ·         繼承Thread類并覆蓋它的run()方法;
              ·        
          實(shí)現(xiàn)Runnable接口并實(shí)現(xiàn)它的run()方法。

            1,繼承Thread類創(chuàng)建線程

          通過繼承Thread類,并覆蓋run()方法,這時就可以用該類的實(shí)例作為線程的目標(biāo)對象。下面的程序定義了SimpleThread類,它繼承了Thread類并覆蓋了run()方法。

          程序SimpleThread.java

          public class SimpleThread extends Thread{

            public SimpleThread(String str){

              super(str);

          }

          public void run(){

              for(int i=0; i<100; i++){

                System.out.println(getName()+" = "+ i);

                try{

                   sleep((int)(Math.random()*100));

                }catch(InterruptedException e){}

              }

          System.out.println(getName()+ " DONE");

          }

          }

          _____________________________________________________________________________

              SimpleThread類繼承了Thread類,并覆蓋了run()方法,該方法就是線程體。

          程序 ThreadTest.java

          public class ThreadTest{

            public static void main(String args[]){

              Thread t1 = new SimpleThread("Runner A");

              Thread t2 = new SimpleThread("Runner B");

              t1.start();

              t2.start();

           }

          }

          _____________________________________________________________________________

          ThreadTest類的main()方法中創(chuàng)建了兩個SimpleThread類的線程對象并調(diào)用線程類的start()方法啟動線程。構(gòu)造線程時沒有指定目標(biāo)對象,所以線程啟動后執(zhí)行本類的run()方法。

          注意,實(shí)際上ThreadTest程序中有三個線程同時運(yùn)行,在應(yīng)用程序的main()方法啟動時,JVM就創(chuàng)建一個主線程,在主線程中可以創(chuàng)建其他線程。

            2,實(shí)現(xiàn)Runnable接口創(chuàng)建線程

          可以定義一個類實(shí)現(xiàn)Runnable接口,然后將該類對象作為線程的目標(biāo)對象。實(shí)現(xiàn)Runnable接口就是實(shí)現(xiàn)run()方法。

          下面程序通過實(shí)現(xiàn)Runnable接口構(gòu)造線程體。

          程序 ThreadTest.java

          class T1 implements Runnable{

            public void run(){

              for(int i=0;i<15;i++)

                System.out.println("Runner A="+i);

            }

          }

          class T2 implements Runnable{

            public void run(){

              for(int j=0;j<15;j++)

                System.out.println("Runner B="+j);

            }

          }

          public class ThreadTest{

            public static void main(String args[]){

              Thread t1=new Thread(new T1(),"Thread A");

              Thread t2=new Thread(new T2(),"Thread B");

              t1.start();

              t2.start();

            }

          }

          _____________________________________________________________________________




              

           



          posted @ 2011-09-01 20:46 Jamie 閱讀(388) | 評論 (0)編輯 收藏

          android 項(xiàng)目下文件的作用

          1, R.java 是建立項(xiàng)目時自動生成的,只讀,用來定義該項(xiàng)目所有資源的索引文件。
          這里面定義了很多常量, 名字與res文件夾的文件名和String.xml里的定義的常量名相同。當(dāng)項(xiàng)目中加入了新的資源時,只需要刷新一下該項(xiàng)目,R.java 便自動生成了。
          2, strings.xml 里面定義了字符串資源。 
              在類中可通過如下方式使用這些資源, Resource r = this.getContext().getResources(); String str = ((String) r.getString(R.string.name));
              在main.xml中可以 android:text="@string/name"
          3,  mail.xml 用來寫UI(布局,控件...)
              主程序繼承Activity類,重寫了void onCreate(Bundle savedInstanceState)方法。 在方法里通過setContentView(R.layout.main)設(shè)置Activity要顯示的布局文件(\layout\main.xml)
          4.  AndroidManifest.xml
              看下默認(rèn)的:

          <?xml version="1.0" encoding="utf-8"?>
          <manifest xmlns:android="      package="com.test"
                android:versionCode="1"
                android:versionName="1.0">
              <uses-sdk android:minSdkVersion="8" />

              <application android:icon="@drawable/icon" android:label="@string/app_name">   //應(yīng)用程序的名字
                  <activity android:name=".WuActivity"   //默認(rèn)啟動哪個Activity
                            android:label="@string/app_name">
                      <intent-filter>
                          <action android:name="android.intent.action.MAIN" />
                          <category android:name="android.intent.category.LAUNCHER" />
                      </intent-filter>
                  </activity>

              </application>
          </manifest>

          posted @ 2011-08-24 02:33 Jamie 閱讀(1028) | 評論 (0)編輯 收藏

          關(guān)于ADT和SDK版本

          用最新的就都用最新的, 不然有可能導(dǎo)致配置過程中出現(xiàn)一些問題。

          我用SDK3.2和ADT 0.9.5配置, 結(jié)果Preferences->Android里設(shè)置路徑出現(xiàn)問題。

          posted @ 2011-08-23 17:45 Jamie 閱讀(255) | 評論 (0)編輯 收藏

          Content is not allowed in prolog

          錯誤可能是由XML有中文格式的字符引起的。

          posted @ 2011-04-20 08:43 Jamie 閱讀(292) | 評論 (0)編輯 收藏

          Jree

          樹控件很適合用來顯示,導(dǎo)航和編輯結(jié)構(gòu)化對象;但是JTree很復(fù)雜,swing中有整個一個包都是針對它的(javax.swing.tree),注意樹控件是顯示的,但是樹數(shù)據(jù)結(jié)構(gòu)是一種集合接口的實(shí)現(xiàn),就如同JList和java.util.List一樣,他們應(yīng)用在不同層,當(dāng)然你使用Jlist來顯示List接口的實(shí)現(xiàn)者那是很般配的。
          *
          **
          關(guān)于樹的術(shù)語如根,節(jié)點(diǎn),葉子,深度,路徑,平衡性,邊,子樹;不需要我這里過多的解釋,任何一本數(shù)據(jù)結(jié)構(gòu)的書籍都會介紹他們。我這里主要是講述樹控件。

          樹遍歷這個概念先提一下:遍歷即逐個訪問,對于樹而言主要有三種:前序,后序,中序遍歷樹的每個節(jié)點(diǎn)。遍歷一般是用遞歸算法來實(shí)現(xiàn)的,三種遍歷法區(qū)別于先訪問樹的那個部分。樹遍歷也是比較難的一個技術(shù),不好掌握,我在大學(xué)時用匯編實(shí)現(xiàn)過這三種算法,到現(xiàn)在還記憶猶新(完全自己找到的規(guī)律),一下來和朋友們分享一下。
          對于一個有兩個子節(jié)點(diǎn)的樹(或多個子節(jié)點(diǎn)),請你沿著樹的外圍畫一個輪廓線:

           

          ———>         >——————
                  /             \
                /                 \
               /_____>____\     

                 這是大致繞樹行走的輪廓線,大家都知道(或許你還不知道)函數(shù)的調(diào)用時控制流的傳遞就是這個樣子的。(控制流是線程執(zhí)行方法時的形象表述)比如一下函數(shù): main(){

               f1();
               f2();
          }//該函數(shù)的控制流向是:先傳給main,再由main()傳給f1,之后退回到mian(),在傳給f2()在由f2退回給main之后結(jié)束程序。異步方法調(diào)用時才會從這個封閉的輪廓中分出一個分支來?,F(xiàn)在來談你如何設(shè)計(jì)一個樹遍歷方法:
          我們來看一個函數(shù)的幾個關(guān)鍵部位,
                 func(){
                  entry入口處
                    
                      中間部位           

                  return出口處   
                }也許你很迷惑這與樹遍歷算法有和關(guān)系,告訴你吧這三個特殊部位就是你在設(shè)計(jì)遞歸時,遞歸函數(shù)應(yīng)該出現(xiàn)的位置,他們出現(xiàn)在不同的位置就是不同的“序”,偽碼如:
          先序遍歷
          traversTree(Node root){
             if(root !=null){
               if(root.isLeaf()){//當(dāng)是葉子時,
                   visit(root);//前序遍歷是先遍歷頁節(jié)點(diǎn)
               }   
                   Node[] children=root.getChildren();//獲取所有子樹
                   for(Node n:children){
                     traversTree(n);//遞歸遍歷所有子樹,注意子樹可能為空。
                    }
             }

          }

          中序遍歷(亦稱廣度優(yōu)先遍歷,總是先遍歷樹的根)

          traversTree(Node root){
             if(root !=null){
               //樹非空
               visit(root); //這是中序遍歷 visit出現(xiàn)與遞歸函數(shù)之前。
              
               Node[] children=root.getChildren();//獲取所有子樹
                   for(Node n:children){
                     traversTree(n);//遞歸遍歷所有子樹,注意子樹可能為空。
                    }
             }

          }

          后序遍歷(亦稱深度優(yōu)先搜索):
          traversTree(Node root){
             if(root !=null){
                  
               Node[] children=root.getChildren();//獲取所有子樹
                   for(Node n:children){
                     traversTree(n);//遞歸遍歷所有子樹,注意子樹可能為空。
                    }
              
               
               visit(root); //這是后序遍歷 visit出現(xiàn)在遞歸函數(shù)之后。
             }

          }

          以上三個算法,可能有點(diǎn)不正確,我沒測試過,時間太久了有點(diǎn)忘了,總之為大家做個參考吧!
          因?yàn)闃浣Y(jié)構(gòu)典型的是應(yīng)用了組合設(shè)計(jì)模式,所以只要涉及到樹肯定涉及遍歷,和遞歸。所以這里羅嗦一下。   所有的樹都是節(jié)點(diǎn)                   
          **
          ***
          swing中Jtree處理樹結(jié)構(gòu)是通過樹模型接口,它實(shí)現(xiàn)了TreeNode接口(在api文檔中竟看不到此信息!),DefaultMutableTreeNode類實(shí)現(xiàn)了TreeNode接口,并提供了前,中,后序的樹遍歷能力。
          JTree圖形化的顯示了樹結(jié)構(gòu)的每一個節(jié)點(diǎn),所有的UI控件都有兩個目的,顯示和輸入(輸入包括數(shù)據(jù)的輸入如JTextField和命令輸入如菜單,按鈕等),JTree既可以用于樹結(jié)構(gòu)的顯示,也可以用于命令的輸入,或使得我們編輯樹節(jié)點(diǎn)。
          樹節(jié)點(diǎn)可以被選中,它由TreeSelectionModel來控制,選擇涉及到維護(hù)作為TreeNode實(shí)例的樹節(jié)點(diǎn)間的路徑軌跡。樹控件典型的可以激發(fā)兩類事件:TreeModelEvent和TreeExpansionEvent,當(dāng)然其他Awt和Swing事件也可由樹控件激發(fā)(看其繼承層次結(jié)構(gòu)即可知)比如MouseListener可用來截取鼠標(biāo)事件。JTree擴(kuò)展了Scrollable接口,可被放在一個滾動面板中。

          JTree的構(gòu)造:可使用默認(rèn)的構(gòu)造方法,提供一個TreeNode作為其根節(jié)點(diǎn),提供一個TreeModel包含所有其它的節(jié)點(diǎn),或提供一個一維數(shù)組,向量,或?qū)ο蟮墓1恚瑢τ谶@些集合中的單個元素,如果它又是一個集合,那么他們會被解釋顯示為子樹,該功能由JTree的內(nèi)部類DynamicUtilTreeNode完成。
          ***
          ****
          TreeModel接口:
          該接口的實(shí)現(xiàn)者為JTree提供顯示的數(shù)據(jù),如果你熟悉MVC模式,你應(yīng)該明白所有的swing或awt控件中模型的作用就是為相應(yīng)的控件提供數(shù)據(jù)。當(dāng)模型的數(shù)據(jù)結(jié)構(gòu)有所變化時它會通知視圖(這里就是JTree)來更新顯示。當(dāng)然模型也可以添加其他的監(jiān)聽器如Jtree的addTreeModelListener,你可以實(shí)現(xiàn)該監(jiān)聽器,來使你自己的類接收模型變化給你的通知。如果你不熟悉MVC模式,請參考POSA卷一或其他資料,順便提一下在我們學(xué)校GUI時都知道有MVC模式的應(yīng)用,往往不知道那個Controller是什么類,其實(shí)就是視圖的監(jiān)聽器,比如ActionListener,注意別被眾多的監(jiān)聽器弄昏了,一類是模型需要添加的,一類是視圖(比如JComponent的子類)需要添加的??刂频牧飨蚧驍?shù)據(jù)的流向是相反的,視圖需要添加的監(jiān)聽器(我們常常實(shí)現(xiàn)他們)才是控制器。

          因?yàn)槟P秃鸵晥D都能夠觸發(fā)事件,比如視圖(JTree等控件)是觸發(fā)用戶輸入導(dǎo)致的事件,而模型觸發(fā)的事件是因?yàn)槟P椭芯S護(hù)的數(shù)據(jù)有所變動才觸發(fā)的(比如,樹模型中樹節(jié)點(diǎn)的增刪,改,或樹路徑的變動)。而他們都使用了觀察者模式,算了不多說了,到時全弄成模式了,會搞昏大家的。繼續(xù)....

          JTree的setModel和getModel方法是用來更換/設(shè)置和獲取模型的方法。你可替換現(xiàn)有JTree的模型,或者你想這樣用,兩個模型,一個用,一個備。如果構(gòu)造模型復(fù)雜耗時的話,先在后臺構(gòu)造好一個在換掉原先的。就如同雙緩沖技術(shù)的思路那樣。
          ****
          *****
          雜項(xiàng):
          DefultTreeModel是對TreeModel接口的默認(rèn)實(shí)現(xiàn)類,
          TreeNode接口可告訴你改實(shí)現(xiàn)者是否為一個葉子,一個父節(jié)點(diǎn)等。MutalbeTreeNode接口擴(kuò)展了TreeNode接口,我們可在該實(shí)現(xiàn)者中存放一個我們自己的類實(shí)例(setUserObject()/getUserObject);
          defaultMutableTreeNode 實(shí)現(xiàn)了MutableTreeNode接口,children()方法返回以一維向量形式存放的直接子節(jié)點(diǎn)的枚舉,也可以使用getChildAt()返回特定索引位置的子節(jié)點(diǎn)(注意子節(jié)點(diǎn)完全可以是一顆子樹)該類提供了前中后序訪問樹的能力:preorderEnumeration(),,breadthFirstEnumeration(),depthFirstEnumeration()postorderEnumeration()最后兩個方法同行為,只不過是不同的稱號而已。

          TreePath:該類用一系列節(jié)點(diǎn)表示一個從樹根到一個節(jié)點(diǎn)的路徑,它是只讀的,提供與其他路徑比較的能力。
          TreeCellRenderrer接口:渲染tree的一個單元的組件,我們自己實(shí)現(xiàn)該接口并用jtree的setCellRenderer()方法替換原先的渲染器,可以是樹節(jié)點(diǎn)在選中,獲取焦點(diǎn),不同的樹狀態(tài)(葉子或父節(jié)點(diǎn),展開,或收縮)等不同的狀態(tài)下的外觀。
          DefaultTreeCellRenderer類是TreeCellRenderrer接口的默認(rèn)實(shí)現(xiàn),它擴(kuò)展了JLabel,并基于以上描述的樹狀態(tài)來渲染樹節(jié)點(diǎn),其提供的屬性包括圖標(biāo),背景色,前景色等,其get和set方法是我們可以訪問的,通過這些方法你當(dāng)然可以換掉樹節(jié)點(diǎn)的圖標(biāo)了。

          CellEditor接口:定義了控制何時編輯將開始,結(jié)束,提取一個新的結(jié)果,是否編輯請求改變當(dāng)前組件的選擇,請參考API文檔看該接口的方法。該接口在JTree和JTable中都有用到。,該接口也可以添加監(jiān)聽器,當(dāng)編輯停止或取消時會激發(fā)ChangeEvents到其所有的注冊處理器哪里。
          TreeCellEditor接口擴(kuò)展了CellEditor接口,jtree的setCellEditor()使得我們可以用任何一個可充當(dāng)編輯器的組件替換掉原來的那個。DefaultCellEditor實(shí)現(xiàn)了該接口,這個編輯器允許使用JTextField,JComboBox或是JCheckBox組件來編輯數(shù)據(jù),其保護(hù)的內(nèi)部類EditorDelegate會響應(yīng)getCellEditorValue()方法把當(dāng)前值返回。DefaultCellEditor僅基于以上三個J控件作為編輯器,其clickCountToStart方法決定鼠標(biāo)單擊幾次會觸發(fā)編輯。默認(rèn)對于JTextField是兩次,JComboBox和JCheckBox是一次,changeEvents會在stopCellEditing()和cancelCellEditing()時激發(fā)。
          DefaultTreeCellEditor擴(kuò)展了DefaultCellEditor類并且是TreeCellEditor的默認(rèn)實(shí)現(xiàn)類,他使用JTextField來編輯節(jié)點(diǎn)數(shù)據(jù),在鍵入ENTER鍵后stopCellEditing()會被調(diào)用。對于樹節(jié)點(diǎn)的編輯我們可添加自己的時間監(jiān)聽器來處理他們。默認(rèn)時編輯開始于節(jié)點(diǎn)被單擊三次或兩次(時間間隔在內(nèi)部會用一個定時器來決定),也可以改變他們的數(shù)目setClickCountToStart();
          JTree的選擇是基于行和樹路徑的,我們可以選擇使用那個。

          TreeSelectionModel接口用于樹選擇模型,支持三種選擇,SINGLE_TREE_SELECTION,
          DISCONTIGUOUS_TREE_SELECTION,CONTIGUOUS_TREE_SELECTION,set/getSelectionMode()可以訪選擇模型。getSelectionPath『s』()會返回一個當(dāng)前選中的樹路徑。DefaultTreeSelectionModel默認(rèn)實(shí)現(xiàn)了該接口,該類提供TreeSelectionlistener通知,當(dāng)樹路徑選擇發(fā)生變化時。

          TreeModelListener實(shí)現(xiàn)者可以偵聽模型變化,TreeSelectionListener用來偵聽視圖JTree的selection(僅有一個方法valueChanged(TreeSlectcionEvent tsEvt));
          TreeExpansionListener用來對樹展開收縮進(jìn)行處理。
          TreeW illExpandListener在樹“將要”展開和收縮時得到通知,你可截獲處理,ExpandVetoException異常如果拋出,那么樹不會展開和收縮。

          TreeModelEvent,用來通知模型的監(jiān)聽器,JTree的數(shù)據(jù)部分或全部發(fā)生了變化。該事件對象封裝了源組件的引用,封裝了一個TreePath或一個用來表示路徑的數(shù)組。
          TreeselectionEvent,視圖會用其通知所有視圖監(jiān)聽器TreeSelectionListeners,選擇發(fā)生了變化。
          TreeExpansionEvent,用來封裝相應(yīng)最近或可能展開或收縮的TreePath,使用getPath()方法訪問樹路徑。
          ExpandVetoException異常可由TreeWillExpandListener拋出,來否決樹路徑的展開和收縮。

          JTree提供的現(xiàn)成方便的UI屬性:
          myJTree.putClientProperty("JTree.lineStyle", "Angled");//更改線型。
          如同其他Swing組件,我們也可以改變默認(rèn)的用于JTree的UI資源(全局性的):
          UIManager.put("Tree.hash",
          new ColorUIResource(Color.lightGray));//改變渲染節(jié)點(diǎn)間edges邊的顏色。
          UIManager.put("Tree.openIcon", new IconUIResource(
          new ImageIcon("myOpenIcon.gif")));//改變一個打開的樹節(jié)點(diǎn)的圖標(biāo)。同理可用于其它情況:Tree.leafIcon, Tree.expandedIcon,和Tree.closedIcon, Tree.collapsedIcon。

          其他控制TreeUI顯示的方法:
          myTree.setRowHeight()//控制樹節(jié)點(diǎn)的行高,
          JTree的UI委托也提供了更改樹外觀的方法(相比于UIManager的方法,這里是局部的)。
          BasicTreeUI basicTreeUI = (BasicTreeUI) myJTree.getUI();
          basicTreeUI.setRightChildIndent(10);
          basicTreeUI.setLeftChildIndent(8);


          以上簡要提及了JTree的方方面面,許多的事件,將聽器模型,請仔細(xì)分析,一定要分清哪些是針對模型的那些是針對視圖的。

          *****
          ******
          簡單的示例,我這里僅用到了最簡單的樹構(gòu)造方法,和一個監(jiān)聽器,在
          以后我的自學(xué)過程中,我會繼續(xù)試用其他的JTree知識,我的JTree學(xué)習(xí)
          最終都是想實(shí)現(xiàn)那個GUI上的授權(quán)控制系統(tǒng),請參考其他篇章,
          至于這里用到的LAndFSysMenu類,在我的其他篇章中有該類的實(shí)現(xiàn)。
          package jTreeDemo;

          import java.awt.Container;
          import javax.swing.*;
          import javax.swing.event.TreeSelectionEvent;
          import javax.swing.event.TreeSelectionListener;
          import lookAndFeelSys.*;
          import userInterfaces.UIUtil;
          import java.awt.*;
          import java.util.Hashtable;
          import java.util.Vector;
          import javax.swing.tree.*;


          public class JTreeTest extends JFrame{

          public static void main(String[] args){
          new JTreeTest("測試");
          }

          public JTreeTest(String title){
             super(title);
             biuldFrame();
          }

             private void biuldFrame(){
              JMenuBar jmb=new JMenuBar();
             
              JMenu jm=new LAndFSysMenu();
              //JMenu jm=new JMenu("hello");
             
              jmb.add(jm);
              this.setJMenuBar(jmb);
             
              buildFrmContent();   
             
              UIUtil.SetComponentDimension(this,0.5,0.6);
              UIUtil.SetComponentToCenterOfScreen(this);
              this.setVisible(true);
              this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
             }
            
             private void buildFrmContent(){
              Container root_c=this.getContentPane();
              JTabbedPane jtp=new JTabbedPane();
              Container c = new JPanel();
              jtp.addTab("靜態(tài)樹組件練習(xí)",c );
              jtp.addTab("事件監(jiān)聽",this.treeDemo2());
               

             root_c.add(jtp);

          c.setLayout(new GridLayout(2,4));
          JScrollPane jsp_1=new JScrollPane();
          JScrollPane jsp_2=new JScrollPane();
          JScrollPane jsp_3=new JScrollPane();
          JScrollPane jsp_4=new JScrollPane();


          /*為JTree準(zhǔn)備顯示的模型*/
          Object[] m1=new String[]{"節(jié)點(diǎn)1","節(jié)點(diǎn)2","節(jié)點(diǎn)3"};
          Object[] m2=new String[][]{
              {"1.1","1.2","1.3"},
              {"2.1","2.2","2.3"},
              {"3.1","3.2","3.3"}
          };
          Vector<Object> m3=new Vector<Object>();
          m3.add("1");
          m3.add("2");
          m3.add(m1);
          m3.add(m2);
          Hashtable<String,Object> m4=new Hashtable<String,Object>();
          m4.put("子一","葉子");
          m4.put("子二", m1);
          m4.put("子三",m3);


          JTree jtr_1=new JTree(m1);
          jsp_1.getViewport().add(jtr_1);
          JTree jtr_2=new JTree(m2);
          jsp_2.getViewport().add(jtr_2);
          JTree jtr_3=new JTree(m3);
          jsp_3.getViewport().add(jtr_3);
          JTree jtr_4=new JTree(m4);
          jsp_4.getViewport().add(jtr_4);


          c.add(jsp_1);
          c.add(jsp_2);
          c.add(jsp_3);
          c.add(jsp_4);

          /*jsp_1.getViewport().add(jtr_1);
          c.add(jsp_1);*/
             }

             /*<<     另一組JTree實(shí)例:*/
             private JPanel treeDemo2(){
              JPanel rsltPanel=new JPanel();
              rsltPanel.setLayout(new BorderLayout());
             
              JLabel jl_msg=new JLabel("此標(biāo)簽用來顯示樹選擇情況");
              JScrollPane jsp_1=new JScrollPane();
              Object[] m=new String[]{"節(jié)點(diǎn)1","節(jié)點(diǎn)2","節(jié)點(diǎn)3"};
              JTree jtr=new JTree(m);
              jtr.getSelectionModel()
              .addTreeSelectionListener(new MySelectionLstnr(
                jl_msg));
             
              jsp_1.getViewport().add(jtr);
             
              rsltPanel.add(jsp_1,BorderLayout.CENTER);
              rsltPanel.add(jl_msg,BorderLayout.SOUTH);
              return rsltPanel;
             }
             class MySelectionLstnr implements TreeSelectionListener{
              //該內(nèi)部類實(shí)現(xiàn)樹監(jiān)聽器,在樹被選中后將選中的節(jié)點(diǎn)
              //信息打印到一個Label上
              private JLabel jl_msg=null;
             
              public MySelectionLstnr(JLabel msgLabel){
              this.jl_msg=msgLabel;
              }
          @Override
          public void valueChanged(TreeSelectionEvent e) {
             // 凡是樹選擇的處理都涉及到樹路徑的處理:
             TreePath path = e.getPath();
             Object[] nodes = path.getPath();
            
             //當(dāng)前選中的節(jié)點(diǎn)是樹路徑上最后一個節(jié)點(diǎn)
               Object selectedNode=nodes[nodes.length-1 ];
               if(this.jl_msg!=null){
               this.jl_msg.setText("選中的節(jié)點(diǎn)上的文本是:"+
                   selectedNode.toString());
               }
          }


             }
             /*另一組JTree實(shí)例:>>*/
          }

           

          ******
          參考Java Swing (Manning出版社)swing hack (orelly出版社)。

          posted @ 2011-03-23 09:09 Jamie| 編輯 收藏

          JTree用法

          import  java.awt.Dimension;
          import  java.awt.Color;
          import  javax.swing.JFrame;
          import  javax.swing.JPanel;
          import  javax.swing.JScrollPane;
          import  javax.swing.JTree;
          import  javax.swing.BoxLayout;
          import  javax.swing.tree.TreePath;
          import  javax.swing.tree.DefaultMutableTreeNode;
          import  javax.swing.tree.DefaultTreeModel;
          /*
          JTree的構(gòu)造函數(shù):
          JTree()
          JTree(Hashtable value)
          JTree(Object[] value)//只有這個構(gòu)造函數(shù)可以創(chuàng)建多個根結(jié)點(diǎn)
          JTree(TreeModel newModel)
          JTree(TreeNode root)
          JTree(TreeNode root, boolean asksAllowsChildren)
          JTree(Vector value)

          */
          public   class  JTreeDemo
          {
           
          public   static   void  main (String[] args)
           {


            
          // 構(gòu)造函數(shù):JTree()
            JTree example1  =   new  JTree();

           

            
            
          // 構(gòu)造函數(shù):JTree(Object[] value)
            Object[] letters =  { " a " " b " " c " " d " " e " };
            JTree example2 
          =   new  JTree (letters);

           


            
          // 構(gòu)造函數(shù):JTree(TreeNode root)(TreeNode空)
            
          // 用空結(jié)點(diǎn)創(chuàng)建樹
            DefaultMutableTreeNode node1  =   new  DefaultMutableTreeNode(); // 定義樹結(jié)點(diǎn)
            JTree example3  =   new  JTree (node1); // 用此樹結(jié)點(diǎn)做參數(shù)調(diào)用 JTree的構(gòu)造函數(shù)創(chuàng)建含有一個根結(jié)點(diǎn)的樹

           


            
          // 構(gòu)造函數(shù):JTree(TreeNode root)(同上,只是TreeNode非空)
            
          // 用一個根結(jié)點(diǎn)創(chuàng)建樹
            DefaultMutableTreeNode node2  =   new  DefaultMutableTreeNode( " Color " );
            JTree example4 
          =   new  JTree (node2); // 結(jié)點(diǎn)不可以顏色,默認(rèn)為白面黑字
            example4.setBackground (Color.lightGray);

           


            
          // 構(gòu)造函數(shù):JTree(TreeNode root, boolean asksAllowsChildren)(同上,只是TreeNode又有不同)
            
          // 使用DefaultMutableTreeNode類先用一個根結(jié)點(diǎn)創(chuàng)建樹,設(shè)置為可添加孩子結(jié)點(diǎn),再添加孩子結(jié)點(diǎn)
            DefaultMutableTreeNode color  =   new  DefaultMutableTreeNode( " Color " true );
            DefaultMutableTreeNode gray 
          =   new  DefaultMutableTreeNode ( " Gray " );
            color.add (gray);
            color.add (
          new  DefaultMutableTreeNode ( " Red " ));
            gray.add (
          new  DefaultMutableTreeNode ( " Lightgray " ));
            gray.add (
          new  DefaultMutableTreeNode ( " Darkgray " ));
            color.add (
          new  DefaultMutableTreeNode ( " Green " ));
            JTree example5 
          =   new  JTree (color);
            
            
            
            
            
          // 構(gòu)造函數(shù):JTree(TreeNode root)(同上,只是TreeNode非空)
            
          // 通過逐個添加結(jié)點(diǎn)創(chuàng)建樹
            DefaultMutableTreeNode biology  =   new  DefaultMutableTreeNode ( " Biology " );
            DefaultMutableTreeNode animal 
          =   new  DefaultMutableTreeNode ( " Animal " );
            DefaultMutableTreeNode mammal 
          =   new  DefaultMutableTreeNode ( " Mammal " );
            DefaultMutableTreeNode horse 
          =   new  DefaultMutableTreeNode ( " Horse " );
            mammal.add (horse);
            animal.add (mammal);
            biology.add (animal);
            JTree example6 
          =   new  JTree (biology);
            horse.isLeaf();
            horse.isRoot();
            
            


            
          // 構(gòu)造函數(shù):JTree(TreeModel newModel)
            
          // 用DefaultMutableTreeNodel類定義一個結(jié)點(diǎn)再用這個結(jié)點(diǎn)做參數(shù)定義一個用DefaultTreeMode
            
          // 創(chuàng)建一個樹的模型,再用JTree的構(gòu)造函數(shù)創(chuàng)建一個樹
            
            DefaultMutableTreeNode root 
          =   new  DefaultMutableTreeNode ( " Root1 " );
            DefaultMutableTreeNode child1 
          =   new  DefaultMutableTreeNode ( " Child1 " );
            DefaultMutableTreeNode child11 
          =   new  DefaultMutableTreeNode ( " Child11 " );
            DefaultMutableTreeNode child111 
          =   new  DefaultMutableTreeNode ( " Child111 " );
            root.add (child1); child1.add (child11); child11.add (child111);
            
            
            
            DefaultTreeModel model 
          =   new  DefaultTreeModel (root);
            
            JTree example7 
          =   new  JTree (model);

           

            JPanel panel 
          =   new  JPanel();
            panel.setLayout (
          new  BoxLayout (panel, BoxLayout.X_AXIS));
            panel.setPreferredSize (
          new  Dimension ( 700 400 ));
            panel.add (
          new  JScrollPane (example1)); // JTree必須放在JScrollPane上
            panel.add ( new  JScrollPane (example2));
            panel.add (
          new  JScrollPane (example3));
            panel.add (
          new  JScrollPane (example4));
            panel.add (
          new  JScrollPane (example5));
            panel.add (
          new  JScrollPane (example6));
            panel.add (
          new  JScrollPane (example7));
            

           

            JFrame frame 
          =   new  JFrame ( " JTreeDemo " );
            frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
            frame.setContentPane (panel);
            frame.pack();
            frame.show();
           }
          }
          ××××××××××××××××××××××××××××××××××××××××××××××

          在實(shí)際開發(fā)過程中會經(jīng)常使用JTree組件,平時會遇到這樣或那樣的問題,在此將偶得一點(diǎn)經(jīng)驗(yàn)寫下來,與大家共享,希望對大家有所幫助。

          private JTree jtNetDevice;//數(shù)組件申明
          private JScrollPane jspTree;//滾動面板申明


          1、初始化
              DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("root");
              jtNetDevice = new JTree(rootNode);
              jtNetDevice.setAutoscrolls(true);
              getTreeSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);//設(shè)置單選模式
              jspTree = new JScrollPane();
              jspTree.getViewport().add(jtNetDevice, null);

          2、三個經(jīng)常使用的取值函數(shù)
            private DefaultTreeModel getTreeModel(){
              return (DefaultTreeModel)jtNetDevice.getModel();
            }

            private DefaultMutableTreeNode getRootNode(){
              return (DefaultMutableTreeNode)getTreeModel().getRoot();
            }
           
            private TreeSelectionModel getTreeSelectionModel(){
              return jtNetDevice.getSelectionModel();
            }
           

          3、根據(jù)node得到path:
            TreePath visiblePath = new TreePath(getTreeModel().getPathToRoot(node));

          4、根據(jù)Path展開到該節(jié)點(diǎn)
            jtNetDevice.makeVisible(visiblePath);

          5、根據(jù)path設(shè)定該節(jié)點(diǎn)選定
            jtNetDevice.setSelectionPath(visiblePath);

          6、選中節(jié)點(diǎn)的方法
            首先,根據(jù)節(jié)點(diǎn)得到樹路徑,其中chosen為需要選中的節(jié)點(diǎn)
            TreePath visiblePath = new TreePath( ( (DefaultTreeModel) jtNetDevice.getModel()).
                                                  getPathToRoot(chosen));
            然后根據(jù)Path選中該節(jié)點(diǎn)
            jtNetDevice.setSelectionPath(visiblePath);

          7、滾動到可見位置
            jtNetDevice.scrollPathToVisible(visiblePath);

          8、給JTree添加右鍵彈出菜單
            void jtNetDevice_mouseReleased(MouseEvent e) {
              if (e.isPopupTrigger()) {
                jPopupMenu1.show(e.getComponent(), e.getX(), e.getY());//彈出右鍵菜單
              }
            }

          9、關(guān)于JTree的展開
             // If expand is true, expands all nodes in the tree.
             // Otherwise, collapses all nodes in the tree.
             public void expandAll(JTree tree, boolean expand) {
                 TreeNode root = (TreeNode)tree.getModel().getRoot();
            
                 // Traverse tree from root
                 expandAll(tree, new TreePath(root), expand);
             }
             private void expandAll(JTree tree, TreePath parent, boolean expand) {
                 // Traverse children
                 TreeNode node = (TreeNode)parent.getLastPathComponent();
                 if (node.getChildCount() >= 0) {
                     for (Enumeration e=node.children(); e.hasMoreElements(); ) {
                         TreeNode n = (TreeNode)e.nextElement();
                         TreePath path = parent.pathByAddingChild(n);
                         expandAll(tree, path, expand);
                     }
                 }
            
                 // Expansion or collapse must be done bottom-up
                 if (expand) {
                     tree.expandPath(parent);
                 } else {
                     tree.collapsePath(parent);
                 }
             }
           

          10、如何遍歷JTree
             // 創(chuàng)建樹
             JTree tree = new JTree();
            
             // 添加樹節(jié)點(diǎn)......
            
             // 遍歷所有節(jié)點(diǎn)
             visitAllNodes(tree);
            
             // 僅遍歷展開的節(jié)點(diǎn)
             visitAllExpandedNodes(tree);
            
             // Traverse all nodes in tree
             public void visitAllNodes(JTree tree) {
                 TreeNode root = (TreeNode)tree.getModel().getRoot();
                 visitAllNodes(root);
             }
             public void visitAllNodes(TreeNode node) {
                 // node is visited exactly once
                 process(node);
            
                 if (node.getChildCount() >= 0) {
                     for (Enumeration e=node.children(); e.hasMoreElements(); ) {
                         TreeNode n = (TreeNode)e.nextElement();
                         visitAllNodes(n);
                     }
                 }
             }
            
             // Traverse all expanded nodes in tree
             public void visitAllExpandedNodes(JTree tree) {
                 TreeNode root = (TreeNode)tree.getModel().getRoot();
                 visitAllExpandedNodes(tree, new TreePath(root));
             }
             public void visitAllExpandedNodes(JTree tree, TreePath parent) {
                 // Return if node is not expanded
                 if (!tree.isVisible(parent)) {
                     return;
                 }
            
                 // node is visible and is visited exactly once
                 TreeNode node = (TreeNode)parent.getLastPathComponent();
                 process(node);
            
                 // Visit all children
                 if (node.getChildCount() >= 0) {
                     for (Enumeration e=node.children(); e.hasMoreElements(); ) {
                         TreeNode n = (TreeNode)e.nextElement();
                         TreePath path = parent.pathByAddingChild(n);
                         visitAllExpandedNodes(tree, path);
                     }
                 }
             }


          posted on 2006-04-04 17:24 SIMONE 閱讀(9202) 評論(1)  編輯  收藏 所屬分類: JAVA

          posted @ 2011-03-23 08:32 Jamie 閱讀(1736) | 評論 (0)編輯 收藏

          GridBagLayout 2

           

          今天終于耐著性子弄懂了GridBagLayout是怎么使用的。
          構(gòu)造函數(shù):
              GirdBagLayout()建立一個新的GridBagLayout管理器。
              GridBagConstraints()建立一個新的GridBagConstraints對象。
              GridBagConstraints(int gridx,int gridy,
                                             int gridwidth,int gridheight,
                                             double weightx,double weighty,
                                             int anchor,int fill, Insets insets,
                                             int ipadx,int ipady)建立一個新的GridBagConstraints對象,并指定其參數(shù)的值。
          看著這一堆的參數(shù)就快煩死了,下面就了解一下參數(shù)的意思:

          參數(shù)說明:
           gridx,gridy    ——    設(shè)置組件的位置,
                             gridx設(shè)置為GridBagConstraints.RELATIVE代表此組件位于之前所加入組件的右邊。
                             gridy設(shè)置為GridBagConstraints.RELATIVE代表此組件位于以前所加入組件的下面。
                            建議定義出gridx,gridy的位置以便以后維護(hù)程序。gridx=0,gridy=0時放在0行0列。

           gridwidth,gridheight    ——    用來設(shè)置組件所占的單位長度與高度,默認(rèn)值皆為1。
                           你可以使用GridBagConstraints.REMAINDER常量,代表此組件為此行或此列的最后一個組件,而且會占據(jù)所有剩余的空間。

           weightx,weighty    ——    用來設(shè)置窗口變大時,各組件跟著變大的比例。
                          當(dāng)數(shù)字越大,表示組件能得到更多的空間,默認(rèn)值皆為0。

           anchor    ——    當(dāng)組件空間大于組件本身時,要將組件置于何處。
                         有CENTER(默認(rèn)值)、NORTH、NORTHEAST、EAST、SOUTHEAST、WEST、NORTHWEST選擇。

           insets    ——    設(shè)置組件之間彼此的間距。
                        它有四個參數(shù),分別是上,左,下,右,默認(rèn)為(0,0,0,0)。

          ipadx,ipady    ——    設(shè)置組件間距,默認(rèn)值為0。

          GridBagLayout里的各種設(shè)置都必須通過GridBagConstraints,因此當(dāng)我們將GridBagConstraints的參數(shù)都設(shè)置
          好了之后,必須new一個GridBagConstraints的對象出來,以便GridBagLayout使用。

          代碼片斷:
                 JButton b;
                GridBagConstraints c;
                int gridx,gridy,gridwidth,gridheight,anchor,fill,ipadx,ipady;
                double weightx,weighty;
                Insets inset;
               
                JFrame f=new JFrame();
               
                GridBagLayout gridbag=new GridBagLayout();
                Container contentPane=f.getContentPane();
                contentPane.setLayout(gridbag);
                 
                  b=new JButton("first");
                  gridx=0;
                  gridy=0;
                  gridwidth=1;
                  gridheight=1;
                  weightx=10;
                  weighty=1;
                  anchor=GridBagConstraints.CENTER;
                  fill=GridBagConstraints.HORIZONTAL;
                  inset=new Insets(0,0,0,0);
                  ipadx=0;
                  ipady=0;
                  c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor,fill,inset,ipadx,ipady);
                  gridbag.setConstraints(b,c);
                  contentPane.add(b);


          GridBagLayout這種管理器是十分靈活的,只不過他寫起來比較麻煩,不過用了之后才發(fā)現(xiàn)他對界面的部署幫助很大。
           


          本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/dracularking/archive/2008/04/22/2314336.aspx

          posted @ 2011-03-18 14:27 Jamie| 編輯 收藏

          GridBagLayout

          下面的是這個界面的一個原始草圖:

           

          正如你所看到的,最終的結(jié)果看上去和計(jì)劃的想法完全一樣。

               你應(yīng)該能看到在草圖里有一些線,這些線是用來把總界面分成若干行和列的,這樣你就很清楚每一個組件放置的格子位置。這就是GridBagLayout里"格"的那一部分,而圖上的數(shù)字就是格的號碼。

          在某種意義上說, 我們可以把GridBagLayout想象成為早些年的HTML3和4,它們都是基于表的布局,Grid的概念就類似rowspan和colspan的意思,只不過換了個名字罷了。

          隨著我們的界面和表格的設(shè)置完成,是時候該進(jìn)行界面布局并開始寫代碼了。

          工作過程

          這一節(jié)我假定你已經(jīng)了解了基本的窗口和組件創(chuàng)建知識。

          通過這篇文章我們最終能在一個frame中布局組件,我們將在以后的文章對界面進(jìn)行改進(jìn)使它更適用。因此,為了了解這整個工作的過程,我們列出了所有的目標(biāo)代碼。

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;
          public class GridBagWindow extends JFrame {
          private JButton searchBtn;
          private JComboBox modeCombo;
          private JLabel tagLbl;
          private JLabel tagModeLbl;
          private JLabel previewLbl;
          private JTable resTable;
          private JTextField tagTxt;
          public GridBagWindow() {
          Container contentPane = getContentPane();
          GridBagLayout gridbag = new GridBagLayout();
          contentPane.setLayout(gridbag);
          GridBagConstraints c = new GridBagConstraints();
          //setting a default constraint value
          c.fill =GridBagConstraints.HORIZONTAL;
          tagLbl = new JLabel("Tags");
          c.gridx = 0; //x grid position
          c.gridy = 0; //y grid position
          gridbag.setConstraints(tagLbl, c); //associate the label with a constraint object
          contentPane.add(tagLbl); //add it to content pane
          tagModeLbl = new JLabel("Tag Mode");
          c.gridx = 0;
          c.gridy = 1;
          gridbag.setConstraints(tagModeLbl, c);
          contentPane.add(tagModeLbl);
          tagTxt = new JTextField("plinth");
          c.gridx = 1;
          c.gridy = 0;
          c.gridwidth = 2;
          gridbag.setConstraints(tagTxt, c);
          contentPane.add(tagTxt);
          String[] options = {"all", "any"};
          modeCombo = new JComboBox(options);
          c.gridx = 1;
          c.gridy = 1;
          c.gridwidth = 1;
          gridbag.setConstraints(modeCombo, c);
          contentPane.add(modeCombo);
          searchBtn = new JButton("Search");
          c.gridx = 1;
          c.gridy = 2;
          gridbag.setConstraints(searchBtn, c);
          contentPane.add(searchBtn);
          resTable = new JTable(5,3);
          c.gridx = 0;
          c.gridy = 3;
          c.gridwidth = 3;
          gridbag.setConstraints(resTable, c);
          contentPane.add(resTable);
          previewLbl = new JLabel("Preview goes here");
          c.gridx = 0;
          c.gridy = 4;
          gridbag.setConstraints(previewLbl, c);
          contentPane.add(previewLbl);
          addWindowListener(new WindowAdapter() {
          public void windowClosing(WindowEvent e) {
          System.exit(0);
          }
          });
          }
          public static void main(String args[]) {
          GridBagWindow window = new GridBagWindow();
          window.setTitle("GridBagWindow");
          window.pack();
          window.setVisible(true);
          }
          }

           

          構(gòu)造方法前的代碼都不是很特殊,都是一些相當(dāng)標(biāo)準(zhǔn)的import和變量定義。但是進(jìn)入構(gòu)造方法后,事情就變得有趣了。

          Container contentPane = getContentPane();

          GridBagLayout gridbag = new GridBagLayout();

          contentPane.setLayout(gridbag);

               我們以GridBagWindow的內(nèi)容面板作為開始來創(chuàng)建一個GridBagLayout對象,準(zhǔn)確地說,這個方法與過去我們所創(chuàng)建 GridLayout對象和BorderLayout對象的方法是一樣的。那么,現(xiàn)在我們就開始來設(shè)置GridBagLayout對象使它作為內(nèi)容面板的 布局。

          GridBagConstraints c = new GridBagConstraints();

               然后我要提到這整個進(jìn)程中的一個獨(dú)特的對象,那就是GridBagConstraints。這個對象在GridBagLayout中控制所 有被安置在其中組件的約束。為了把一個組件增加到你的GridBagLayout中去,你首先必須將它與一個GridBagConstraints對象建 立連接。

          GridBagConstraints可以從11個方面來進(jìn)行控制和操縱,也可以給你提供一些幫助。這些內(nèi)容是:

          • Gridx——組件的橫向坐標(biāo)
          • Girdy——組件的縱向坐標(biāo)
          • Gridwidth——組件的橫向?qū)挾龋簿褪侵附M件占用的列數(shù),這與HTML的colspan類似
          • Gridheight——組件的縱向長度,也就是指組件占用的行數(shù),這與HTML的rowspan類似
          • Weightx——指行的權(quán)重,告訴布局管理器如何分配額外的水平空間
          • Weighty——指列的權(quán)重,告訴布局管理器如何分配額外的垂直空間
          • Anchor——告訴布局管理器組件在表格空間中的位置
          • Fill——如果顯示區(qū)域比組件的區(qū)域大的時候,可以用來控制組件的行為。控制組件是垂直填充,還是水平填充,或者兩個方向一起填充
          • Insets——指組件與表格空間四周邊緣的空白區(qū)域的大小
          • Ipadx—— 組件間的橫向間距,組件的寬度就是這個組件的最小寬度加上ipadx值
          • ipady—— 組件間的縱向間距,組件的高度就是這個組件的最小高度加上ipady值

               可能對于一個組件的每一個實(shí)例你都需要為它建立一個單獨(dú)的GridBagConstraints;然而,這種方法我們并不推薦使用。最好的方法是,當(dāng)你調(diào)用它的時候把對象設(shè)置為默認(rèn)值,然后針對于每一個組件改變其相應(yīng)的域。

               這個方法具有通用性,因?yàn)樵谝恍┯蛑?,比如insets、padx、pady和fill這些域,對于每一個組件來說一般都是相同的,因此這樣對一個域進(jìn)行設(shè)置就會更輕松了,也能更輕松的在另外的組件中改變某些域的值。

               如果在改變了某些域值之后,你想回到原始的域值的話,你應(yīng)該在增加下一個組件之前進(jìn)行改變。這種方法使你更容易明白你正在修改的內(nèi)容,也能使你更容易明白在一連串對象中的這11個參數(shù)的作用。

               也許你現(xiàn)在對這些內(nèi)容還是一知半解,不過事實(shí)上一旦你理解了GridBagConstraints,值得安慰的是你以后做再困難的工作都會游刃有余了。

          所以,如果我們已經(jīng)明白了GridBagConstraints的詳細(xì)用法了,那么現(xiàn)在就讓我們來看看在實(shí)際應(yīng)用中應(yīng)該如何來實(shí)現(xiàn)它:

          tagLbl = new JLabel("Tags");
          c.gridx = 0; //x grid position
          c.gridy = 0; //y grid position
          gridbag.setConstraints(tagLbl, c); //設(shè)置標(biāo)簽的限制

          contentPane.add(tagLbl); //增加到內(nèi)容面板

          我們所做的是示例我們的標(biāo)簽、分配給它一個格位置,將它與一個約束對象聯(lián)系起來并把它增加到我們的內(nèi)容面板中。

          tagModeLbl = new JLabel("Tag Mode");
          c.gridx = 0;
          c.gridy = 1;
          gridbag.setConstraints(tagModeLbl, c);

          contentPane.add(tagModeLbl);

             請注意,雖然我們已經(jīng)在我們的約束對象中把gridx的值設(shè)置為0,但是在這里我們?nèi)匀灰獙λM(jìn)行重新設(shè)置——這樣做沒有其它原因,只是為了增加可讀性。

               下面,我們增加一個文本域以便能存儲我們希望能搜索到的關(guān)鍵字,再增加一個組合框以便用來搜索多個關(guān)鍵字。除了我們希望的文本域有兩列之外,這個概念其他的方面都與上面所說的是相同的,所以,我們需要在增加組合框之前重新設(shè)置文本域的值。

          tagTxt = new JTextField("plinth");
          c.gridx = 1;
          c.gridy = 0;
          c.gridwidth = 2;
          gridbag.setConstraints(tagTxt, c);
          contentPane.add(tagTxt);

          String[] options = {"all", "any"};
          modeCombo = new JComboBox(options);
          c.gridx = 1;
          c.gridy = 1;
          c.gridwidth = 1;
          gridbag.setConstraints(modeCombo, c);
          contentPane.add(modeCombo);

                 做了這些之后,我們再在內(nèi)容面板中增加一些其余的簡單組件,這時候我們就能夠?yàn)g覽它了;其余的代碼應(yīng)該不會出現(xiàn)任何問題了。

          到這個階段,我們應(yīng)該已經(jīng)得到了一個類似于我們先前所設(shè)計(jì)的界面了。

          posted @ 2011-02-24 10:32 Jamie 閱讀(489) | 評論 (0)編輯 收藏

          JComboBox

          7-4:JComboBox的使用:
          類層次結(jié)構(gòu)圖:
             java.lang.Object
              --java.awt.Component
               --java.awt.Container
                --javax.swing.JComponent
                 --javax.swing.JComboBox
             構(gòu)造函數(shù):
              JComboBox():建立一個新的JComboBox組件。
              JComboBox(ComboBoxModel aModel):用ListModel建立一個新的JComboBox組件。
              JComboBox(Object[] items):利用Array對象建立一個新的JComboBox組件。
              JComboBox(Vector items):利用Vector對象建立一個新的JComboBox組件。
          7-4-1:建立一般的JComboBox:
          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;
          import java.util.Vector;

          public class JComboBox1{
          public static void main(String[] args){
          JFrame f=new JFrame("JComboBox1");
          Container contentPane=f.getContentPane();
          contentPane.setLayout(new GridLayout(1,2));
          String[] s = {"美國","日本","大陸","英國","法國","意大利","澳洲","韓國"};
          Vector v=new Vector();
          v.addElement("Nokia 8850");
          v.addElement("Nokia 8250");
          v.addElement("Motorola v8088");
          v.addElement("Motorola v3850");
          v.addElement("Panasonic 8850");
              v.addElement("其它");
             
              JComboBox combo1=new JComboBox(s);
              combo1.addItem("中國");//利用JComboBox類所提供的addItem()方法,加入一個項(xiàng)目到此JComboBox中。
              combo1.setBorder(BorderFactory.createTitledBorder("你最喜歡到哪個國家玩呢?"));
              JComboBox combo2=new JComboBox(v);
              combo2.setBorder(BorderFactory.createTitledBorder("你最喜歡哪一種手機(jī)呢?"));  
              contentPane.add(combo1);
              contentPane.add(combo2);
              f.pack();
              f.show();
              f.addWindowListener(new WindowAdapter(){
              public void windowClosing(WindowEvent e){
              System.exit(0);
              }
              });
          }
          }
          7-4-2:利用ComboModel構(gòu)造JComboBox:
              如同JList一般,在JComboBox中也有一個構(gòu)造函數(shù)是利用某種Model來構(gòu)造。如下所示:
                JComboBox(COmboBoxModel aModel)
             ComboBoxModel是一個interface,里面定義了兩個方法,分別是setSelectedItem()與getSelectedItem().這兩個方法目的是讓用
          戶選取某個項(xiàng)目后,可正確地顯示出用戶所選取的項(xiàng)目。下面是這兩個方法的詳細(xì)定義:
          ComboBoxModel interface定義的方法:
             Object    getSelectedItem():返回所選取的項(xiàng)目值。
             Void      setSelectedItem(Object anItem):設(shè)置所選取的項(xiàng)目值.

          與JList不同的是,JComboBox是利用ComboBoxModel,而不是ListModel.不過ComboBoxModel interface是繼承ListModel interface
          ,因此若我們要利用ComboBoxModel來構(gòu)造JComboBox,除了要實(shí)作ComboBoxModel的兩個方法外,還必須實(shí)作ListModel的所定義的4個
          方法,這樣的做法可說相當(dāng)麻煩。
             在介紹JList時我們曾經(jīng)提到AbstractListModel這個抽象類。這個抽象類實(shí)作了ListModel interface中的addListDataListener
          ()、removeListDataListener()這兩個方法。因此若我們繼承AbstractListModel,則可少掉實(shí)作這兩個方法,只需要實(shí)作
          getElementAt()、getSize()、setSelectedItem()與getSelectedItem()這4個方法。這樣的作法就顯得比較簡單一點(diǎn).

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class JComboBox2{
          String[] s= {"美國","日本","大陸","英國","法國","意大利","澳洲","韓國"};
          public JComboBox2(){
              JFrame f=new JFrame("JComboBox2");
              Container contentPane=f.getContentPane();
             
              ComboBoxModel mode=new UserDefineComboBoxModel();
              JComboBox combo=new JComboBox(mode);
              combo.setBorder(BorderFactory.createTitledBorder("你最喜歡到哪個國家去玩?"));
              contentPane.add(combo);
              f.pack();
              f.show();
              f.addWindowListener(new WindowAdapter(){
              public void windowClosing(WindowEvent e){
              System.exit(0);
              }
              });  
          }
          public static void main(String[] args){
          new JComboBox2();
          }

          class UserDefineComboBoxModel extends AbstractListModel implements ComboBoxModel{
          String item=null;
          public Object getElementAt(int index){
             return s[index++];
          }
               //由于繼承AbstractListModel抽象類。因此我們分別在程序中實(shí)作了getElementAt()與getSize()方法。
          public int getSize(){
              return s.length;
          }
               //由于我們實(shí)現(xiàn)了ComboBoxModel interface.因此我們必須在程序中實(shí)作setSelectedItem()與getSelectedItem()方法.
          public void setSelectedItem(Object anItem){
                item=(String)anItem;
               }
               public Object getSelectedItem(){
                  return item;
               }
          }
          }
             當(dāng)程序要show出JComboBox時,系統(tǒng)會先自動調(diào)用getSize()方法,看看這個JComboBox長度有多少,然后再調(diào)用getElementAt()
          方法,將String Array s中的值填入JComboBox中。當(dāng)用戶選擇項(xiàng)目時,系統(tǒng)會調(diào)用getSelectedItem()方法,返回所選取的項(xiàng)目,并
          利用setSelectedItem()方法,將選取項(xiàng)目放在JComboBox最前端。
             getElementAt()方法中的“index”參數(shù),系統(tǒng)會自動由0計(jì)算,不過要自己作累加的操作,如程序中:
              return s[index++];
          如同JList一般,java對于JComboBox也提供了另一個類,DefaultComboBoxModel實(shí)體類。此類繼承了AbstractListModel抽象類,也
          實(shí)作了ComboBoxModel interface.因此你不需要再實(shí)作getSize()、getElementAt()、setSelectedItem()與getSelectedItem()方法。
          利用DefaultComboBoxModel這個類我們可以很方便地做到動態(tài)更改JComboBox的項(xiàng)目值。當(dāng)你沒有必要自己定義特殊的ComboBoxModel
          時,使用DefaultComboBoxModel就顯得非常的方便,我們來看下面的例子:

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class JComboBox3{
             String[] s = {"美國","日本","大陸","英國","法國","意大利","澳洲","韓國"};
             public JComboBox3(){
                JFrame f=new JFrame("JComboBox3");
                Container contentPane=f.getContentPane();
               
                ComboBoxModel mode=new AModel();
                JComboBox combo=new JComboBox(mode);
                combo.setBorder(BorderFactory.createTitledBorder("您最喜歡到哪個國家玩呢?"));
                contentPane.add(combo);
                f.pack();
                f.show();
                f.addWindowListener(new WindowAdapter(){
              public void windowClosing(WindowEvent e){
              System.exit(0);
              }
                });  
             }
             public static void main(String[] args){
                new JComboBox3();
             }
             class AModel extends DefaultComboBoxModel{
             AModel(){
             for (int i=0;i<s.length;i++)
             addElement(s[i]);
             }
             }
          }
              1.由于AModel繼承DefaultComboBoxModel實(shí)體類,由AModel可得到一個ComboBoxModel實(shí)體對象。
              2.我們使AModel繼承DefaultComboBoxModel實(shí)體類,因此就不需要再實(shí)作getElementAt()、getSize()、setSelectedItem()與
                getSelectedItem()這4個方法,直接將所要的項(xiàng)目用addElement()方法加入即可。系統(tǒng)會自動將所加入的項(xiàng)目放進(jìn)一個Vector
                中,并在輸出JComboBox時自動調(diào)用getSize()與getElementAt()方法。
          7-4-3:建立有圖像的JComboBox:
              在上一節(jié)中我們利用ListCellRenderer interface在JList中加入Icon圖像,而要在JComboBox中加入圖像的方法也是一樣的。
          我們必須實(shí)作ListCellRenderer interface所定義的方法getListCellRendererComponent.以下為這個方法的定義:
          要先了解ListCellRenderer interface.我們必須由這個interface所定義的方法,將圖像畫在JComboBox中的每個項(xiàng)目。
          ListCellRenderer interface里只定義了一個方法,那就是getListCellRendererComponent,不過這個參數(shù)有點(diǎn)多,我們把它列出來
          看看:
          public Component getListCellRendererComponent(JList list,
                                                        Object value,
                                                        int index,
                                                        boolean isSelected,
                                                        boolean cellHasFocus)
          list:即所要畫上的圖像的JComboBox組件。
          value:JComboBox項(xiàng)目值,如JComboBox.getModel().getElementAt(index)所返回的值。
          index:為JComboBox項(xiàng)目的索引值,由0開始。
          isSelected與cellHasFocus:判斷JComboBox中的項(xiàng)目是否有被選取或是有焦點(diǎn)置入。
          上面這4個參數(shù)會在你設(shè)置JComboBox的繪圖樣式(setCellRenderer())時自動的由JComboBox組件提供,你只要關(guān)心怎么控制
          getListCellRendererComponent()方法中的4個參數(shù),而無需擔(dān)心怎么參數(shù)傳入。
             要在JList中加入Icon圖像的技巧就是將JComboBox中的每一個項(xiàng)目當(dāng)作是JLabel,因?yàn)镴Label在使用文字與圖像上非常的方便,要設(shè)置JComboBox的圖像,
          必須使用setRenderer(ListCellRenderer cellRenderer){注:我們在JList中畫上圖像是利用JList所提供的setCellRenderer(ListCellRenderer
          cellRenderer)方法,讀者請小心}這個方法。我們來看下面這個范例,你就能明白了!

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class JComboBox4{
          String[] s={"西瓜","蘋果","草莓","香蕉","葡萄"};
          public JComboBox4(){
          JFrame f=new JFrame("JComboBox");
          Container contentPane=f.getContentPane();

          JComboBox combo=new JComboBox(s);
          combo.setBorder(BorderFactory.createTitledBorder("你最喜歡吃哪些水果?"));
          combo.setRenderer(new ACellRenderer());
          combo.setMaximumRowCount(3);

          contentPane.add(combo);
                f.pack();
                f.show();
                f.addWindowListener(new WindowAdapter(){
              public void windowClosing(WindowEvent e){
              System.exit(0);
              }
                });    
          }
          public static void main(String[] args){
          new JComboBox4();
          }
          }
          class ACellRenderer extends JLabel implements ListCellRenderer{
          ACellRenderer(){
             setOpaque(true);
          }
          public Component getListCellRendererComponent(JList list,
                                                        Object value,
                                                        int index,
                                                        boolean isSelected,
                                                        boolean cellHasFocus){
              if (value!=null){
                setText(value.toString());
                setIcon(new ImageIcon(".\\icons\\fruit"+(index+1)+".jpg"));
              }
              if (isSelected){
                 setBackground(list.getSelectionBackground());
                 setForeground(list.getSelectionForeground());
              }else{
                 setBackground(list.getBackground());
                 setForeground(list.getForeground());
              }                                   
              return this;      
              }                                             
          }
              各們讀者在運(yùn)行這個程序時會發(fā)現(xiàn),即使JComboBox的選項(xiàng)中有圖標(biāo),但在選后圖標(biāo)卻不會顯示在顯示列中,原因是在上面程序中
          我們以String Array s建立JComboBox:
                JComboBox combo=new JComboBox(s);
                String Array s里面放的只是水果名稱,而并沒有圖標(biāo)。當(dāng)我們使用setRenderer()方法來JComboBox時,只會繪制JComboBox的
          選項(xiàng)部份,而最后顯示在JComboBox上的值還是以String Array s為依據(jù)。因此JComboBox顯示列就只會顯示文字而已,而不會顯示出
          圖形。要解決這個問題,我們必須改變JComboBox所傳入的參數(shù)內(nèi)容,也就是將原來的String Array s更改成具有圖形的數(shù)據(jù)項(xiàng)。在
          此我們是利用JComboBox(Object[] items)來建立有圖像的JComboBox,我們所傳進(jìn)去的Object Array不應(yīng)該只有文字,而必須連圖標(biāo)一
          并傳入。我們修改上個范例修改如下:

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class JComboBox5
          {
              String[] s = {"西瓜","蘋果","草莓","香蕉","葡萄"};
              ImageIcon[] icons = new ImageIcon[5];;
             
              public JComboBox5()
              {
                  JFrame f = new JFrame("JComboBox");
                  Container contentPane = f.getContentPane();
                  ItemObj[] obj = new ItemObj[5];
                 
                  for(int i=0; i < 5; i++)
                  {
                      icons[i] = new ImageIcon(".\\icons\\fruit"+(i+1)+".jpg");
                      obj[i] = new ItemObj(s[i],icons[i]);
                  }
                 
                  JComboBox combo = new JComboBox(obj);//利用ItemObj Array obj當(dāng)作是JComboBox的參數(shù)傳入,構(gòu)造出JComboBox.
                  combo.setBorder(BorderFactory.createTitledBorder("您喜歡吃哪些水果?"));
                  combo.setRenderer(new ACellRenderer());
                  combo.setMaximumRowCount(3);
                 
                  contentPane.add(combo);
                  f.pack();
                  f.show();
                  f.addWindowListener(new WindowAdapter() {
                      public void windowClosing(WindowEvent e) {
                              System.exit(0);
                      }
                  });
              }
             
              public static void main(String args[])
              {
                  new JComboBox5();
              }
          }

          class ItemObj
          {
              String name;
              ImageIcon icon;
             
              public ItemObj(String name, ImageIcon icon){
                  this.name = name;
                  this.icon = icon;
              }
          }
             
          class ACellRenderer extends JLabel implements ListCellRenderer
          {
              ACellRenderer()
              {
                  setOpaque(true);
              }
             
              public Component getListCellRendererComponent(JList list,
                                                            Object value,
                                                            int index,
                                                            boolean isSelected,
                                                            boolean cellHasFocus)
              {
                  if (value != null)
                  {
                      setText(((ItemObj)value).name);
                      setIcon(((ItemObj)value).icon);
                  }

                  if (isSelected) {
                      setBackground(list.getSelectionBackground());
                      setForeground(list.getSelectionForeground());
                  }
                  else {
                      setBackground(list.getBackground());
                      setForeground(list.getForeground());
                  }

                  return this;
              }   
          }

             你可以發(fā)現(xiàn),第一欄顯示有圖標(biāo)顯示出來了。當(dāng)然你也可以利用ComboBoxModel方式來構(gòu)造出有圖標(biāo)的JComboBox.我們來看下面
          的例子:

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class JComboBox6{
          String[] s={"西瓜","蘋果","草莓","香蕉","葡萄"};
          ImageIcon[] icons=new ImageIcon[5];
          public JComboBox6(){
              JFrame f=new JFrame("JComboBox");
              Container contentPane=f.getContentPane();
                  for(int i=0; i < 5; i++)
                  {
                      icons[i] = new ImageIcon(".\\icons\\fruit"+(i+1)+".jpg");
                  }
                  ComboBoxModel mode=new AModel();
                  JComboBox combo=new JComboBox(mode);
                  combo.setBorder(BorderFactory.createTitledBorder("您喜歡吃哪些水果?"));
                  combo.setRenderer(new ACellRenderer());
                  combo.setMaximumRowCount(3);
                 
                  contentPane.add(combo);
                  f.pack();
                  f.show();
                  f.addWindowListener(new WindowAdapter() {
                      public void windowClosing(WindowEvent e) {
                              System.exit(0);
                      }
                  });
          }
          public static void main(String[] args){
          new JComboBox6();
          }
          /*我們用JComboBox(ComboBoxModel aModel)來構(gòu)造圖標(biāo)的JComboBox,因此我們在程序中編寫一個繼承DefaultComboBoxModel的
          ComboBoxModel.
          */
          class AModel extends DefaultComboBoxModel{
          AModel(){
             for (int i=0;i<s.length;i++){
                ItemObj obj=new ItemObj(s[i],icons[i]);
                addElement(obj);
             }
          }
          }
          }
          class ItemObj
          {
              String name;
              ImageIcon icon;
             
              public ItemObj(String name, ImageIcon icon){
                  this.name = name;
                  this.icon = icon;
              }
          }
             
          class ACellRenderer extends JLabel implements ListCellRenderer
          {
              ACellRenderer()
              {
                  setOpaque(true);
              }
             
              public Component getListCellRendererComponent(JList list,
                                                            Object value,
                                                            int index,
                                                            boolean isSelected,
                                                            boolean cellHasFocus)
              {
                  if (value != null)
                  {
                      setText(((ItemObj)value).name);
                      setIcon(((ItemObj)value).icon);
                  }

                  if (isSelected) {
                      setBackground(list.getSelectionBackground());
                      setForeground(list.getSelectionForeground());
                  }
                  else {
                      setBackground(list.getBackground());
                      setForeground(list.getForeground());
                  }

                  return this;
              }   
          }

             我們用JComboBox(ComboBoxModel aModel)來構(gòu)造圖標(biāo)的JComboBox,因此我們在程序中編寫一個繼承DefaultComboBoxModel的
          ComboBoxModel.

          7-4-4:建立可自行輸入的JComboBox:
          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class JComboBox7
          {
              String[] fontsize = {"12","14","16","18","20","22","24","26","28"};
              String defaultMessage = "請選擇或直接輸入文字大?。?;
             
              public JComboBox7()
              {
                  JFrame f = new JFrame("JComboBox");
                  Container contentPane = f.getContentPane();
                 
                  JComboBox combo = new JComboBox(fontsize);
                  combo.setBorder(BorderFactory.createTitledBorder("請選擇你要的文字大小"));
                  combo.setEditable(true);//將JComboBox設(shè)成是可編輯的.
                  ComboBoxEditor editor = combo.getEditor();//getEditor()方法返回ComboBoxEditor對象,如果你查看手冊,你就會發(fā)
                   //現(xiàn)ComboBoxEditor是個接口(interface),因此你可以自行實(shí)作這個接口,制作自己想要的ComboBoxEditor組件。但通常
                   //我們不需要這么做,因?yàn)槟J(rèn)的ComboBoxEditor是使用JTextField,這已經(jīng)足夠應(yīng)付大部份的情況了。
                 
                  //configureEditor()方法會初始化JComboBox的顯示項(xiàng)目。例如例子中一開始就出現(xiàn):"請選擇或直接輸入文字大??!"這個
                  //字符串。
                  combo.configureEditor(editor, defaultMessage);
                 
                  contentPane.add(combo);
                  f.pack();
                  f.show();
                  f.addWindowListener(new WindowAdapter() {
                      public void windowClosing(WindowEvent e) {
                              System.exit(0);
                      }
                  });
              }
             
              public static void main(String args[])
              {
                  new JComboBox7();
              }
          }


          7-4-5:JComboBox的事件處理:
              JComboBox的事件處理亦可分為兩種,一種是取得用戶選取的項(xiàng)目;另一種是用戶在JComboBox上自行輸入完畢后按下[Enter]鍵,
          運(yùn)作相對應(yīng)的工作。對于第一種事件的處理,我們使用ItemListener.對于第二種事件的處理,我們使用ActionListener.
              這個范例用戶可以選取所要的字號,字號的變化會呈現(xiàn)在JLabel上,并可讓用戶自行輸入字體的大小。當(dāng)用戶按下[Enter]鍵后
          ,若用戶輸入的值不在選項(xiàng)上時,此輸入值會增加至JComboBox中,并將輸入字體的大小顯示在JLabel上。

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class JComboBox8 implements ItemListener,ActionListener{
          String[] fontsize={"12","14","16","18","20","22","24","26","28"};
          String defaultMessage="請選擇或直接輸入文字大小!";
          Font font=null;
          JComboBox combo=null;
          JLabel label=null;

          public JComboBox8(){
          JFrame f=new JFrame("JComboBox");
          Container contentPane=f.getContentPane();
          contentPane.setLayout(new GridLayout(2,1));
          label=new JLabel("Swing",JLabel.CENTER);
          font=new Font("SansSerif",Font.PLAIN,12);
          label.setFont(font);

          combo=new JComboBox(fontsize);
          combo.setBorder(BorderFactory.createTitledBorder("請選擇你要的文字大小:"));
          combo.setEditable(true);
          ComboBoxEditor editor=combo.getEditor();
          combo.configureEditor(editor,defaultMessage);
          combo.addItemListener(this);0
          combo.addActionListener(this);

          contentPane.add(label);
          contentPane.add(combo);
                f.pack();
                f.show();
                f.addWindowListener(new WindowAdapter(){
              public void windowClosing(WindowEvent e){
              System.exit(0);
              }
                });  
          }
             public static void main(String[] args){
             new JComboBox8();
             }
             public void actionPerformed(ActionEvent e){
             boolean isaddItem=true;
             int fontsize=0;
             String tmp=(String)combo.getSelectedItem();
             //判斷用戶所輸入的項(xiàng)目是否有重復(fù),若有重復(fù)則不增加到JComboBox中。
             try{
             fontsize=Integer.parseInt(tmp);
             for(int i=0;i<combo.getItemCount();i++){
             if (combo.getItemAt(i).equals(tmp)){
             isaddItem=false;
             break;
             }
             }
             if (isaddItem){
             combo.insertItemAt(tmp,0);//插入項(xiàng)目tmp到0索引位置(第一列中).
             }
             font=new Font("SansSerif",Font.PLAIN,fontsize);
             label.setFont(font);  
             }catch(NumberFormatException ne){
             combo.getEditor().setItem("你輸入的值不是整數(shù)值,請重新輸入!");
             }
             }
             public void itemStateChanged(ItemEvent e){//ItemListener界面只有itemStateChanged()一個方法,在此實(shí)作它。
             if (e.getStateChange()==ItemEvent.SELECTED){//當(dāng)用戶的選擇改變時,則在JLabel上會顯示出Swing目前字形大小信息.
             int fontsize=0;
             try{
             fontsize=Integer.parseInt((String)e.getItem());
             label.setText("Swing 目前字形大小:"+fontsize);  
             }catch(NumberFormatException ne){//若所輸入的值不是整數(shù),則不作任何的操作.
            
             }
             }
             }
          }

          posted @ 2011-02-17 08:24 Jamie 閱讀(2788) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 太和县| 清丰县| 额济纳旗| 兴业县| 东台市| 富平县| 蓬莱市| 巴楚县| 公安县| 香港 | 阳泉市| 灵寿县| 秦皇岛市| 太和县| 赤峰市| 华亭县| 建德市| 忻城县| 玉树县| 新蔡县| 陈巴尔虎旗| 禄丰县| 新化县| 绥中县| 兴仁县| 陵川县| 南阳市| 玛沁县| 定州市| 舞阳县| 平武县| 武安市| 宣城市| 赤壁市| 威信县| 灌阳县| 淅川县| 罗田县| 西畴县| 马公市| 澎湖县|