<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    java something

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

    2010年9月21日

    Activity生命周期

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

    先啟動(dòng)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 閱讀(222) | 評(píng)論 (0)編輯 收藏

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

    本程序可以控制3個(gè)線程按順序執(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 閱讀(1769) | 評(píng)論 (2)編輯 收藏

    線程的同步與共享

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

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

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

      1,線程的生命周期

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



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

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

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

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

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

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

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

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

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

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

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




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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    程序 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類中定義了一個(gè)布爾變量flag,同時(shí)定義了一個(gè)stopRun()方法,在其中將該變量設(shè)置為false。在主程序中通過(guò)調(diào)用該方法,從而改變?cè)撟兞康闹担沟?/span>run()方法的while循環(huán)條件不滿足,從而實(shí)現(xiàn)結(jié)束線程的運(yùn)行。

    說(shuō)明  Thread類中除了stop()方法被標(biāo)注為不推薦(deprecated) 使用外,suspend()方法和resume()方法也被標(biāo)明不推薦使用,這兩個(gè)方法原來(lái)用作線程的掛起和恢復(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時(shí)間,使當(dāng)前正在運(yùn)行的線程進(jìn)入就緒狀態(tài)。這時(shí)有幾種可能的情況:如果沒(méi)有其他的線程處于就緒狀態(tài)等待運(yùn)行,該線程會(huì)立即繼續(xù)運(yùn)行;如果有等待的線程,此時(shí)線程回到就緒狀態(tài)狀態(tài)與其他線程競(jìng)爭(zhēng)CPU時(shí)間,當(dāng)有比該線程優(yōu)先級(jí)高的線程時(shí),高優(yōu)先級(jí)的線程進(jìn)入運(yùn)行狀態(tài),當(dāng)沒(méi)有比該線程優(yōu)先級(jí)高的線程時(shí),但有同優(yōu)先級(jí)的線程,則由線程調(diào)度程序來(lái)決定哪個(gè)線程進(jìn)入運(yùn)行狀態(tài),因此線程調(diào)用yield()方法只能將CPU時(shí)間讓給具有同優(yōu)先級(jí)的或高優(yōu)先級(jí)的線程而不能讓給低優(yōu)先級(jí)的線程。

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

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

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

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

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

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

    ③ 有時(shí)要求當(dāng)前線程的執(zhí)行在另一個(gè)線程執(zhí)行結(jié)束后再繼續(xù)執(zhí)行,這時(shí)可以調(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é)束或指定的時(shí)間過(guò)后,當(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()方法,等待某個(gè)條件變量,此時(shí)該線程進(jìn)入阻塞狀態(tài)。直到被通知(調(diào)用了notify()notifyAll()方法)結(jié)束等待后,線程回到就緒狀態(tài)。

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

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



















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

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

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

    Thread類和Runnable接口

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

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

     

    Runnable接口中只定義了一個(gè)方法:

    ·         public abstract void run()

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


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

    ·         public Thread()

    ·         public Thread(Runnable target)

    ·         public Thread(String name)

    ·         public Thread(Runnable target, String name)
    target為線程運(yùn)行的目標(biāo)對(duì)象,即線程調(diào)用start()方法啟動(dòng)后運(yùn)行那個(gè)對(duì)象的run()方法,該對(duì)象的類型為Runnable,若沒(méi)有指定目標(biāo)對(duì)象,則以當(dāng)前類對(duì)象為目標(biāo)對(duì)象,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)建線程

    通過(guò)繼承Thread類,并覆蓋run()方法,這時(shí)就可以用該類的實(shí)例作為線程的目標(biāo)對(duì)象。下面的程序定義了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)建了兩個(gè)SimpleThread類的線程對(duì)象并調(diào)用線程類的start()方法啟動(dòng)線程。構(gòu)造線程時(shí)沒(méi)有指定目標(biāo)對(duì)象,所以線程啟動(dòng)后執(zhí)行本類的run()方法。

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

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

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

    下面程序通過(guò)實(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 閱讀(383) | 評(píng)論 (0)編輯 收藏

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

    1, R.java 是建立項(xiàng)目時(shí)自動(dòng)生成的,只讀,用來(lái)定義該項(xiàng)目所有資源的索引文件。
    這里面定義了很多常量, 名字與res文件夾的文件名和String.xml里的定義的常量名相同。當(dāng)項(xiàng)目中加入了新的資源時(shí),只需要刷新一下該項(xiàng)目,R.java 便自動(dòng)生成了。
    2, strings.xml 里面定義了字符串資源。 
        在類中可通過(guò)如下方式使用這些資源, Resource r = this.getContext().getResources(); String str = ((String) r.getString(R.string.name));
        在main.xml中可以 android:text="@string/name"
    3,  mail.xml 用來(lái)寫UI(布局,控件...)
        主程序繼承Activity類,重寫了void onCreate(Bundle savedInstanceState)方法。 在方法里通過(guò)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)啟動(dòng)哪個(gè)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 閱讀(1024) | 評(píng)論 (0)編輯 收藏

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

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

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

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

    Content is not allowed in prolog

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

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

    Jree

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

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

     

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

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

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

            return出口處   
          }也許你很迷惑這與樹遍歷算法有和關(guān)系,告訴你吧這三個(gè)特殊部位就是你在設(shè)計(jì)遞歸時(shí),遞歸函數(shù)應(yīng)該出現(xiàn)的位置,他們出現(xiàn)在不同的位置就是不同的“序”,偽碼如:
    先序遍歷
    traversTree(Node root){
       if(root !=null){
         if(root.isLeaf()){//當(dāng)是葉子時(shí),
             visit(root);//前序遍歷是先遍歷頁(yè)節(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ù)之后。
       }

    }

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

    JTree的構(gòu)造:可使用默認(rèn)的構(gòu)造方法,提供一個(gè)TreeNode作為其根節(jié)點(diǎn),提供一個(gè)TreeModel包含所有其它的節(jié)點(diǎn),或提供一個(gè)一維數(shù)組,向量,或?qū)ο蟮墓1恚瑢?duì)于這些集合中的單個(gè)元素,如果它又是一個(gè)集合,那么他們會(huì)被解釋顯示為子樹,該功能由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)有所變化時(shí)它會(huì)通知視圖(這里就是JTree)來(lái)更新顯示。當(dāng)然模型也可以添加其他的監(jiān)聽器如Jtree的addTreeModelListener,你可以實(shí)現(xiàn)該監(jiān)聽器,來(lái)使你自己的類接收模型變化給你的通知。如果你不熟悉MVC模式,請(qǐng)參考POSA卷一或其他資料,順便提一下在我們學(xué)校GUI時(shí)都知道有MVC模式的應(yīng)用,往往不知道那個(gè)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ù)有所變動(dòng)才觸發(fā)的(比如,樹模型中樹節(jié)點(diǎn)的增刪,改,或樹路徑的變動(dòng))。而他們都使用了觀察者模式,算了不多說(shuō)了,到時(shí)全弄成模式了,會(huì)搞昏大家的。繼續(xù)....

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

    TreePath:該類用一系列節(jié)點(diǎn)表示一個(gè)從樹根到一個(gè)節(jié)點(diǎn)的路徑,它是只讀的,提供與其他路徑比較的能力。
    TreeCellRenderrer接口:渲染tree的一個(gè)單元的組件,我們自己實(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)來(lái)渲染樹節(jié)點(diǎn),其提供的屬性包括圖標(biāo),背景色,前景色等,其get和set方法是我們可以訪問(wèn)的,通過(guò)這些方法你當(dāng)然可以換掉樹節(jié)點(diǎn)的圖標(biāo)了。

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

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

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

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

    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")));//改變一個(gè)打開的樹節(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);


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

    *****
    ******
    簡(jiǎn)單的示例,我這里僅用到了最簡(jiǎn)單的樹構(gòu)造方法,和一個(gè)監(jiān)聽器,在
    以后我的自學(xué)過(guò)程中,我會(huì)繼續(xù)試用其他的JTree知識(shí),我的JTree學(xué)習(xí)
    最終都是想實(shí)現(xiàn)那個(gè)GUI上的授權(quán)控制系統(tǒng),請(qǐ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("測(cè)試");
    }

    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)簽用來(lái)顯示樹選擇情況");
        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)
        //信息打印到一個(gè)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)是樹路徑上最后一個(gè)節(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è)構(gòu)造函數(shù)可以創(chuàng)建多個(gè)根結(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)建含有一個(gè)根結(jié)點(diǎn)的樹

     


      
    // 構(gòu)造函數(shù):JTree(TreeNode root)(同上,只是TreeNode非空)
      
    // 用一個(gè)根結(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類先用一個(gè)根結(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非空)
      
    // 通過(guò)逐個(gè)添加結(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類定義一個(gè)結(jié)點(diǎn)再用這個(gè)結(jié)點(diǎn)做參數(shù)定義一個(gè)用DefaultTreeMode
      
    // 創(chuàng)建一個(gè)樹的模型,再用JTree的構(gòu)造函數(shù)創(chuàng)建一個(gè)樹
      
      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ā)過(guò)程中會(huì)經(jīng)常使用JTree組件,平時(shí)會(huì)遇到這樣或那樣的問(wèn)題,在此將偶得一點(diǎn)經(jīng)驗(yàn)寫下來(lái),與大家共享,希望對(duì)大家有所幫助。

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


    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、三個(gè)經(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、滾動(dòng)到可見位置
      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) 評(píng)論(1)  編輯  收藏 所屬分類: JAVA

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

    GridBagLayout 2

     

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

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

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

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

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

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

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

    GridBagLayout里的各種設(shè)置都必須通過(guò)GridBagConstraints,因此當(dāng)我們將GridBagConstraints的參數(shù)都設(shè)置
    好了之后,必須new一個(gè)GridBagConstraints的對(duì)象出來(lái),以便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這種管理器是十分靈活的,只不過(guò)他寫起來(lái)比較麻煩,不過(guò)用了之后才發(fā)現(xiàn)他對(duì)界面的部署幫助很大。
     


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

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

    GridBagLayout

    下面的是這個(gè)界面的一個(gè)原始草圖:

     

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

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

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

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

    工作過(guò)程

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

    通過(guò)這篇文章我們最終能在一個(gè)frame中布局組件,我們將在以后的文章對(duì)界面進(jìn)行改進(jìn)使它更適用。因此,為了了解這整個(gè)工作的過(guò)程,我們列出了所有的目標(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)容面板作為開始來(lái)創(chuàng)建一個(gè)GridBagLayout對(duì)象,準(zhǔn)確地說(shuō),這個(gè)方法與過(guò)去我們所創(chuàng)建 GridLayout對(duì)象和BorderLayout對(duì)象的方法是一樣的。那么,現(xiàn)在我們就開始來(lái)設(shè)置GridBagLayout對(duì)象使它作為內(nèi)容面板的 布局。

    GridBagConstraints c = new GridBagConstraints();

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

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

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

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

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

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

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

    所以,如果我們已經(jīng)明白了GridBagConstraints的詳細(xì)用法了,那么現(xiàn)在就讓我們來(lái)看看在實(shí)際應(yīng)用中應(yīng)該如何來(lái)實(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)簽、分配給它一個(gè)格位置,將它與一個(gè)約束對(duì)象聯(lián)系起來(lái)并把它增加到我們的內(nèi)容面板中。

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

    contentPane.add(tagModeLbl);

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

         下面,我們?cè)黾右粋€(gè)文本域以便能存儲(chǔ)我們希望能搜索到的關(guān)鍵字,再增加一個(gè)組合框以便用來(lái)搜索多個(gè)關(guān)鍵字。除了我們希望的文本域有兩列之外,這個(gè)概念其他的方面都與上面所說(shuō)的是相同的,所以,我們需要在增加組合框之前重新設(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);

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

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

    posted @ 2011-02-24 10:32 Jamie 閱讀(481) | 評(píng)論 (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():建立一個(gè)新的JComboBox組件。
        JComboBox(ComboBoxModel aModel):用ListModel建立一個(gè)新的JComboBox組件。
        JComboBox(Object[] items):利用Array對(duì)象建立一個(gè)新的JComboBox組件。
        JComboBox(Vector items):利用Vector對(duì)象建立一個(gè)新的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 = {"美國(guó)","日本","大陸","英國(guó)","法國(guó)","意大利","澳洲","韓國(guó)"};
    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("中國(guó)");//利用JComboBox類所提供的addItem()方法,加入一個(gè)項(xiàng)目到此JComboBox中。
        combo1.setBorder(BorderFactory.createTitledBorder("你最喜歡到哪個(gè)國(guó)家玩呢?"));
        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è)構(gòu)造函數(shù)是利用某種Model來(lái)構(gòu)造。如下所示:
          JComboBox(COmboBoxModel aModel)
       ComboBoxModel是一個(gè)interface,里面定義了兩個(gè)方法,分別是setSelectedItem()與getSelectedItem().這兩個(gè)方法目的是讓用
    戶選取某個(gè)項(xiàng)目后,可正確地顯示出用戶所選取的項(xiàng)目。下面是這兩個(gè)方法的詳細(xì)定義:
    ComboBoxModel interface定義的方法:
       Object    getSelectedItem():返回所選取的項(xiàng)目值。
       Void      setSelectedItem(Object anItem):設(shè)置所選取的項(xiàng)目值.

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

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

    public class JComboBox2{
    String[] s= {"美國(guó)","日本","大陸","英國(guó)","法國(guó)","意大利","澳洲","韓國(guó)"};
    public JComboBox2(){
        JFrame f=new JFrame("JComboBox2");
        Container contentPane=f.getContentPane();
       
        ComboBoxModel mode=new UserDefineComboBoxModel();
        JComboBox combo=new JComboBox(mode);
        combo.setBorder(BorderFactory.createTitledBorder("你最喜歡到哪個(gè)國(guó)家去玩?"));
        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時(shí),系統(tǒng)會(huì)先自動(dòng)調(diào)用getSize()方法,看看這個(gè)JComboBox長(zhǎng)度有多少,然后再調(diào)用getElementAt()
    方法,將String Array s中的值填入JComboBox中。當(dāng)用戶選擇項(xiàng)目時(shí),系統(tǒng)會(huì)調(diào)用getSelectedItem()方法,返回所選取的項(xiàng)目,并
    利用setSelectedItem()方法,將選取項(xiàng)目放在JComboBox最前端。
       getElementAt()方法中的“index”參數(shù),系統(tǒng)會(huì)自動(dòng)由0計(jì)算,不過(guò)要自己作累加的操作,如程序中:
        return s[index++];
    如同JList一般,java對(duì)于JComboBox也提供了另一個(gè)類,DefaultComboBoxModel實(shí)體類。此類繼承了AbstractListModel抽象類,也
    實(shí)作了ComboBoxModel interface.因此你不需要再實(shí)作getSize()、getElementAt()、setSelectedItem()與getSelectedItem()方法。
    利用DefaultComboBoxModel這個(gè)類我們可以很方便地做到動(dòng)態(tài)更改JComboBox的項(xiàng)目值。當(dāng)你沒(méi)有必要自己定義特殊的ComboBoxModel
    時(shí),使用DefaultComboBoxModel就顯得非常的方便,我們來(lái)看下面的例子:

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

    public class JComboBox3{
       String[] s = {"美國(guó)","日本","大陸","英國(guó)","法國(guó)","意大利","澳洲","韓國(guó)"};
       public JComboBox3(){
          JFrame f=new JFrame("JComboBox3");
          Container contentPane=f.getContentPane();
         
          ComboBoxModel mode=new AModel();
          JComboBox combo=new JComboBox(mode);
          combo.setBorder(BorderFactory.createTitledBorder("您最喜歡到哪個(gè)國(guó)家玩呢?"));
          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可得到一個(gè)ComboBoxModel實(shí)體對(duì)象。
        2.我們使AModel繼承DefaultComboBoxModel實(shí)體類,因此就不需要再實(shí)作getElementAt()、getSize()、setSelectedItem()與
          getSelectedItem()這4個(gè)方法,直接將所要的項(xiàng)目用addElement()方法加入即可。系統(tǒng)會(huì)自動(dòng)將所加入的項(xiàng)目放進(jìn)一個(gè)Vector
          中,并在輸出JComboBox時(shí)自動(dòng)調(diào)用getSize()與getElementAt()方法。
    7-4-3:建立有圖像的JComboBox:
        在上一節(jié)中我們利用ListCellRenderer interface在JList中加入Icon圖像,而要在JComboBox中加入圖像的方法也是一樣的。
    我們必須實(shí)作ListCellRenderer interface所定義的方法getListCellRendererComponent.以下為這個(gè)方法的定義:
    要先了解ListCellRenderer interface.我們必須由這個(gè)interface所定義的方法,將圖像畫在JComboBox中的每個(gè)項(xiàng)目。
    ListCellRenderer interface里只定義了一個(gè)方法,那就是getListCellRendererComponent,不過(guò)這個(gè)參數(shù)有點(diǎn)多,我們把它列出來(lái)
    看看:
    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個(gè)參數(shù)會(huì)在你設(shè)置JComboBox的繪圖樣式(setCellRenderer())時(shí)自動(dòng)的由JComboBox組件提供,你只要關(guān)心怎么控制
    getListCellRendererComponent()方法中的4個(gè)參數(shù),而無(wú)需擔(dān)心怎么參數(shù)傳入。
       要在JList中加入Icon圖像的技巧就是將JComboBox中的每一個(gè)項(xiàng)目當(dāng)作是JLabel,因?yàn)镴Label在使用文字與圖像上非常的方便,要設(shè)置JComboBox的圖像,
    必須使用setRenderer(ListCellRenderer cellRenderer){注:我們?cè)贘List中畫上圖像是利用JList所提供的setCellRenderer(ListCellRenderer
    cellRenderer)方法,讀者請(qǐng)小心}這個(gè)方法。我們來(lái)看下面這個(gè)范例,你就能明白了!

    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)行這個(gè)程序時(shí)會(huì)發(fā)現(xiàn),即使JComboBox的選項(xiàng)中有圖標(biāo),但在選后圖標(biāo)卻不會(huì)顯示在顯示列中,原因是在上面程序中
    我們以String Array s建立JComboBox:
          JComboBox combo=new JComboBox(s);
          String Array s里面放的只是水果名稱,而并沒(méi)有圖標(biāo)。當(dāng)我們使用setRenderer()方法來(lái)JComboBox時(shí),只會(huì)繪制JComboBox的
    選項(xiàng)部份,而最后顯示在JComboBox上的值還是以String Array s為依據(jù)。因此JComboBox顯示列就只會(huì)顯示文字而已,而不會(huì)顯示出
    圖形。要解決這個(gè)問(wèn)題,我們必須改變JComboBox所傳入的參數(shù)內(nèi)容,也就是將原來(lái)的String Array s更改成具有圖形的數(shù)據(jù)項(xiàng)。在
    此我們是利用JComboBox(Object[] items)來(lái)建立有圖像的JComboBox,我們所傳進(jìn)去的Object Array不應(yīng)該只有文字,而必須連圖標(biāo)一
    并傳入。我們修改上個(gè)范例修改如下:

    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)顯示出來(lái)了。當(dāng)然你也可以利用ComboBoxModel方式來(lái)構(gòu)造出有圖標(biāo)的JComboBox.我們來(lái)看下面
    的例子:

    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)來(lái)構(gòu)造圖標(biāo)的JComboBox,因此我們?cè)诔绦蛑芯帉懸粋€(gè)繼承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)來(lái)構(gòu)造圖標(biāo)的JComboBox,因此我們?cè)诔绦蛑芯帉懸粋€(gè)繼承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 = "請(qǐng)選擇或直接輸入文字大小!";
       
        public JComboBox7()
        {
            JFrame f = new JFrame("JComboBox");
            Container contentPane = f.getContentPane();
           
            JComboBox combo = new JComboBox(fontsize);
            combo.setBorder(BorderFactory.createTitledBorder("請(qǐng)選擇你要的文字大小"));
            combo.setEditable(true);//將JComboBox設(shè)成是可編輯的.
            ComboBoxEditor editor = combo.getEditor();//getEditor()方法返回ComboBoxEditor對(duì)象,如果你查看手冊(cè),你就會(huì)發(fā)
             //現(xiàn)ComboBoxEditor是個(gè)接口(interface),因此你可以自行實(shí)作這個(gè)接口,制作自己想要的ComboBoxEditor組件。但通常
             //我們不需要這么做,因?yàn)槟J(rèn)的ComboBoxEditor是使用JTextField,這已經(jīng)足夠應(yīng)付大部份的情況了。
           
            //configureEditor()方法會(huì)初始化JComboBox的顯示項(xiàng)目。例如例子中一開始就出現(xiàn):"請(qǐng)選擇或直接輸入文字大小!"這個(gè)
            //字符串。
            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)作相對(duì)應(yīng)的工作。對(duì)于第一種事件的處理,我們使用ItemListener.對(duì)于第二種事件的處理,我們使用ActionListener.
        這個(gè)范例用戶可以選取所要的字號(hào),字號(hào)的變化會(huì)呈現(xiàn)在JLabel上,并可讓用戶自行輸入字體的大小。當(dāng)用戶按下[Enter]鍵后
    ,若用戶輸入的值不在選項(xiàng)上時(shí),此輸入值會(huì)增加至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="請(qǐng)選擇或直接輸入文字大小!";
    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("請(qǐng)選擇你要的文字大小:"));
    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ù)值,請(qǐng)重新輸入!");
       }
       }
       public void itemStateChanged(ItemEvent e){//ItemListener界面只有itemStateChanged()一個(gè)方法,在此實(shí)作它。
       if (e.getStateChange()==ItemEvent.SELECTED){//當(dāng)用戶的選擇改變時(shí),則在JLabel上會(huì)顯示出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 閱讀(2782) | 評(píng)論 (0)編輯 收藏

    httpclient

     

    HttpClient 是 Apache Jakarta Common 下的子項(xiàng)目,可以用來(lái)提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。本文首先介紹 HTTPClient,然后根據(jù)作者實(shí)際工作經(jīng)驗(yàn)給出了一些常見問(wèn)題的解決方法。 HttpClient簡(jiǎn)介 HTTP 協(xié)議可能是現(xiàn)在 Internet 上使用得最多、最重要的協(xié)議了,越來(lái)越多的 Java 應(yīng)用程序需要直接通過(guò) HTTP 協(xié)議來(lái)訪問(wèn)網(wǎng)絡(luò)資源。雖然在 JDK 的 java.net 包中已經(jīng)提供了訪問(wèn) HTTP 協(xié)議的基本功能,但是對(duì)于大部分應(yīng)用程序來(lái)說(shuō),JDK 庫(kù)本身提供的功能還不夠豐富和靈活。HttpClient 是 Apache Jakarta Common 下的子項(xiàng)目,用來(lái)提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。HttpClient 已經(jīng)應(yīng)用在很多的項(xiàng)目中,比如 Apache Jakarta 上很著名的另外兩個(gè)開源項(xiàng)目 Cactus 和 HTMLUnit 都使用了 HttpClient,更多使用 HttpClient 的應(yīng)用可以參見http://wiki.apache.org/jakarta-httpclient/HttpClientPowered。HttpClient 項(xiàng)目非常活躍,使用的人還是非常多的。目前 HttpClient 版本是在 2005.10.11 發(fā)布的 3.0 RC4 。 

    HttpClient 功能介紹
    以下列出的是 HttpClient 提供的主要的功能,要知道更多詳細(xì)的功能可以參見 HttpClient 的主頁(yè)。
    
    • 實(shí)現(xiàn)了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
      
    • 支持自動(dòng)轉(zhuǎn)向
      
    • 支持 HTTPS 協(xié)議
      
    • 支持代理服務(wù)器等

    下面將逐一介紹怎樣使用這些功能。首先,我們必須安裝好 HttpClient。

    HttpClient 基本功能的使用  

    GET 方法 

    使用 HttpClient 需要以下 6 個(gè)步驟:

    1. 創(chuàng)建 HttpClient 的實(shí)例
     
    2. 創(chuàng)建某種連接方法的實(shí)例,在這里是 GetMethod。在 GetMethod 的構(gòu)造函數(shù)中傳入待連接的地址

    3. 調(diào)用第一步中創(chuàng)建好的實(shí)例的 execute 方法來(lái)執(zhí)行第二步中創(chuàng)建好的 method 實(shí)例

    4. 讀 response

    5. 釋放連接。無(wú)論執(zhí)行方法是否成功,都必須釋放連接

    6. 對(duì)得到后的內(nèi)容進(jìn)行處理

    根據(jù)以上步驟,我們來(lái)編寫用GET方法來(lái)取得某網(wǎng)頁(yè)內(nèi)容的代碼。
    大部分情況下 HttpClient 默認(rèn)的構(gòu)造函數(shù)已經(jīng)足夠使用。
    HttpClient httpClient = new HttpClient();
     
    創(chuàng)建GET方法的實(shí)例。在GET方法的構(gòu)造函數(shù)中傳入待連接的地址即可。用GetMethod將會(huì)自動(dòng)處理轉(zhuǎn)發(fā)過(guò)程,如果想要把自動(dòng)處理轉(zhuǎn)發(fā)過(guò)程去掉的話,可以調(diào)用方法setFollowRedirects(false)。
    GetMethod getMethod = new GetMethod("http://www.ibm.com/");
     
    調(diào)用實(shí)例httpClient的executeMethod方法來(lái)執(zhí)行g(shù)etMethod。由于是執(zhí)行在網(wǎng)絡(luò)上的程序,在運(yùn)行executeMethod方法的時(shí)候,需要處理兩個(gè)異常,分別是HttpException和IOException。引起第一種異常的原因主要可能是在構(gòu)造getMethod的時(shí)候傳入的協(xié)議不對(duì),比如不小心將"http"寫成"htp",或者服務(wù)器端返回的內(nèi)容不正常等,并且該異常發(fā)生是不可恢復(fù)的;第二種異常一般是由于網(wǎng)絡(luò)原因引起的異常,對(duì)于這種異常 (IOException),HttpClient會(huì)根據(jù)你指定的恢復(fù)策略自動(dòng)試著重新執(zhí)行executeMethod方法。HttpClient的恢復(fù)策略可以自定義(通過(guò)實(shí)現(xiàn)接口HttpMethodRetryHandler來(lái)實(shí)現(xiàn))。通過(guò)httpClient的方法setParameter設(shè)置你實(shí)現(xiàn)的恢復(fù)策略,本文中使用的是系統(tǒng)提供的默認(rèn)恢復(fù)策略,該策略在碰到第二類異常的時(shí)候?qū)⒆詣?dòng)重試3次。executeMethod返回值是一個(gè)整數(shù),表示了執(zhí)行該方法后服務(wù)器返回的狀態(tài)碼,該狀態(tài)碼能表示出該方法執(zhí)行是否成功、需要認(rèn)證或者頁(yè)面發(fā)生了跳轉(zhuǎn)(默認(rèn)狀態(tài)下GetMethod的實(shí)例是自動(dòng)處理跳轉(zhuǎn)的)等。
    //設(shè)置成了默認(rèn)的恢復(fù)策略,在發(fā)生異常時(shí)候?qū)⒆詣?dòng)重試3次,在這里你也可以設(shè)置成自定義的恢復(fù)策略
    getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
        new DefaultHttpMethodRetryHandler());
    //執(zhí)行g(shù)etMethod
    int statusCode = client.executeMethod(getMethod);
    if (statusCode != HttpStatus.SC_OK) {
      System.err.println("Method failed: " + getMethod.getStatusLine());
    }

    在返回的狀態(tài)碼正確后,即可取得內(nèi)容。取得目標(biāo)地址的內(nèi)容有三種方法:第一種,getResponseBody,該方法返回的是目標(biāo)的二進(jìn)制的byte流;第二種,getResponseBodyAsString,這個(gè)方法返回的是String類型,值得注意的是該方法返回的String的編碼是根據(jù)系統(tǒng)默認(rèn)的編碼方式,所以返回的String值可能編碼類型有誤,在本文的"字符編碼"部分中將對(duì)此做詳細(xì)介紹;第三種,getResponseBodyAsStream,這個(gè)方法對(duì)于目標(biāo)地址中有大量數(shù)據(jù)需要傳輸是最佳的。在這里我們使用了最簡(jiǎn)單的getResponseBody方法。
     
    byte[] responseBody = method.getResponseBody();
     
     釋放連接。無(wú)論執(zhí)行方法是否成功,都必須釋放連接
     method.releaseConnection();
     
    處理內(nèi)容。在這一步中根據(jù)你的需要處理內(nèi)容,在例子中只是簡(jiǎn)單的將內(nèi)容打印到控制臺(tái)
     System.out.println(new String(responseBody));
     
     import java.io.IOException;
    import org.apache.commons.httpclient.*;
    import org.apache.commons.httpclient.methods.GetMethod;
    import org.apache.commons.httpclient.params.HttpMethodParams;
    public class GetSample{
      public static void main(String[] args) {
      //構(gòu)造HttpClient的實(shí)例
      HttpClient httpClient = new HttpClient();
      //創(chuàng)建GET方法的實(shí)例
      GetMethod getMethod = new GetMethod("http://www.ibm.com");
      //使用系統(tǒng)提供的默認(rèn)的恢復(fù)策略
      getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
        new DefaultHttpMethodRetryHandler());
      try {
       //執(zhí)行g(shù)etMethod
       int statusCode = httpClient.executeMethod(getMethod);
       if (statusCode != HttpStatus.SC_OK) {
        System.err.println("Method failed: "
          + getMethod.getStatusLine());
       }
       //讀取內(nèi)容
       byte[] responseBody = getMethod.getResponseBody();
       //處理內(nèi)容
       System.out.println(new String(responseBody));
      } catch (HttpException e) {
       //發(fā)生致命的異常,可能是協(xié)議不對(duì)或者返回的內(nèi)容有問(wèn)題
       System.out.println("Please check your provided http address!");
       e.printStackTrace();
      } catch (IOException e) {
       //發(fā)生網(wǎng)絡(luò)異常
       e.printStackTrace();
      } finally {
       //釋放連接
       getMethod.releaseConnection();
      }
     }
    }

     
     

    POST方法

    根據(jù)RFC2616,對(duì)POST的解釋如下:POST方法用來(lái)向目的服務(wù)器發(fā)出請(qǐng)求,要求它接受被附在請(qǐng)求后的實(shí)體,并把它當(dāng)作請(qǐng)求隊(duì)列(Request-Line)中請(qǐng)求URI所指定資源的附加新子項(xiàng)。POST被設(shè)計(jì)成用統(tǒng)一的方法實(shí)現(xiàn)下列功能:

    • 對(duì)現(xiàn)有資源的注釋(Annotation of existing resources)
      
    • 向電子公告欄、新聞組,郵件列表或類似討論組發(fā)送消息
      
    • 提交數(shù)據(jù)塊,如將表單的結(jié)果提交給數(shù)據(jù)處理過(guò)程
      
    • 通過(guò)附加操作來(lái)擴(kuò)展數(shù)據(jù)庫(kù)
    調(diào)用HttpClient中的PostMethod與GetMethod類似,除了設(shè)置PostMethod的實(shí)例與GetMethod有些不同之外,剩下的步驟都差不多。在下面的例子中,省去了與GetMethod相同的步驟,只說(shuō)明與上面不同的地方,并以登錄清華大學(xué)BBS為例子進(jìn)行說(shuō)明。
     構(gòu)造PostMethod之前的步驟都相同,與GetMethod一樣,構(gòu)造PostMethod也需要一個(gè)URI參數(shù),在本例中,登錄的地址是http://www.newsmth.net/bbslogin2.php。在創(chuàng)建了PostMethod的實(shí)例之后,需要給method實(shí)例填充表單的值,在BBS的登錄表單中需要有兩個(gè)域,第一個(gè)是用戶名(域名叫id),第二個(gè)是密碼(域名叫passwd)。表單中的域用類NameValuePair來(lái)表示,該類的構(gòu)造函數(shù)第一個(gè)參數(shù)是域名,第二參數(shù)是該域的值;將表單所有的值設(shè)置到PostMethod中用方法setRequestBody。另外由于BBS登錄成功后會(huì)轉(zhuǎn)向另外一個(gè)頁(yè)面,但是HttpClient對(duì)于要求接受后繼服務(wù)的請(qǐng)求,比如POST和PUT,不支持自動(dòng)轉(zhuǎn)發(fā),因此需要自己對(duì)頁(yè)面轉(zhuǎn)向做處理。具體的頁(yè)面轉(zhuǎn)向處理請(qǐng)參見下面的"自動(dòng)轉(zhuǎn)向"部分。代碼如下
     
    String url = "http://www.newsmth.net/bbslogin2.php";
    PostMethod postMethod = new PostMethod(url);
    // 填入各個(gè)表單域的值
    NameValuePair[] data = { new NameValuePair("id", "youUserName"),
    new NameValuePair("passwd", "yourPwd") };
    // 將表單的值放入postMethod中
    postMethod.setRequestBody(data);
    // 執(zhí)行postMethod
    int statusCode = httpClient.executeMethod(postMethod);
    // HttpClient對(duì)于要求接受后繼服務(wù)的請(qǐng)求,象POST和PUT等不能自動(dòng)處理轉(zhuǎn)發(fā)
    // 301或者302
    if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
    statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
        // 從頭中取出轉(zhuǎn)向的地址
     Header locationHeader = postMethod.getResponseHeader("location");
        String location = null;
        if (locationHeader != null) {
         location = locationHeader.getValue();
         System.out.println("The page was redirected to:" + location);
        } else {
         System.err.println("Location field value is null.");
        }
        return;
    }

     
     
     

    字符編碼 

    某目標(biāo)頁(yè)的編碼可能出現(xiàn)在兩個(gè)地方,第一個(gè)地方是服務(wù)器返回的http頭中,另外一個(gè)地方是得到的html/xml頁(yè)面中。

     
  • 在http頭的Content-Type字段可能會(huì)包含字符編碼信息。例如可能返回的頭會(huì)包含這樣子的信息:Content-Type: text/html; charset=UTF-8。這個(gè)頭信息表明該頁(yè)的編碼是UTF-8,但是服務(wù)器返回的頭信息未必與內(nèi)容能匹配上。比如對(duì)于一些雙字節(jié)語(yǔ)言國(guó)家,可能服務(wù)器返回的編碼類型是UTF-8,但真正的內(nèi)容卻不是UTF-8編碼的,因此需要在另外的地方去得到頁(yè)面的編碼信息;但是如果服務(wù)器返回的編碼不是UTF-8,而是具體的一些編碼,比如gb2312等,那服務(wù)器返回的可能是正確的編碼信息。通過(guò)method對(duì)象的getResponseCharSet()方法就可以得到http頭中的編碼信息。
    
  • 對(duì)于象xml或者h(yuǎn)tml這樣的文件,允許作者在頁(yè)面中直接指定編碼類型。比如在html中會(huì)有<meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>這樣的標(biāo)簽;或者在xml中會(huì)有<?xml version="1.0" encoding="gb2312"?>這樣的標(biāo)簽,在這些情況下,可能與http頭中返回的編碼信息沖突,需要用戶自己判斷到底那種編碼類型應(yīng)該是真正的編碼。
  • 自動(dòng)轉(zhuǎn)向

    根據(jù)RFC2616中對(duì)自動(dòng)轉(zhuǎn)向的定義,主要有兩種:301和302。301表示永久的移走(Moved Permanently),當(dāng)返回的是301,則表示請(qǐng)求的資源已經(jīng)被移到一個(gè)固定的新地方,任何向該地址發(fā)起請(qǐng)求都會(huì)被轉(zhuǎn)到新的地址上。302表示暫時(shí)的轉(zhuǎn)向,比如在服務(wù)器端的servlet程序調(diào)用了sendRedirect方法,則在客戶端就會(huì)得到一個(gè)302的代碼,這時(shí)服務(wù)器返回的頭信息中l(wèi)ocation的值就是sendRedirect轉(zhuǎn)向的目標(biāo)地址。

    HttpClient支持自動(dòng)轉(zhuǎn)向處理,但是象POST和PUT方式這種要求接受后繼服務(wù)的請(qǐng)求方式,暫時(shí)不支持自動(dòng)轉(zhuǎn)向,因此如果碰到POST方式提交后返回的是301或者302的話需要自己處理。就像剛才在POSTMethod中舉的例子:如果想進(jìn)入登錄BBS后的頁(yè)面,必須重新發(fā)起登錄的請(qǐng)求,請(qǐng)求的地址可以在頭字段location中得到。不過(guò)需要注意的是,有時(shí)候location返回的可能是相對(duì)路徑,因此需要對(duì)location返回的值做一些處理才可以發(fā)起向新地址的請(qǐng)求。

    另外除了在頭中包含的信息可能使頁(yè)面發(fā)生重定向外,在頁(yè)面中也有可能會(huì)發(fā)生頁(yè)面的重定向。引起頁(yè)面自動(dòng)轉(zhuǎn)發(fā)的標(biāo)簽是:<meta http-equiv="refresh" content="5; url=http://www.ibm.com/us">。如果你想在程序中也處理這種情況的話得自己分析頁(yè)面來(lái)實(shí)現(xiàn)轉(zhuǎn)向。需要注意的是,在上面那個(gè)標(biāo)簽中url的值也可以是一個(gè)相對(duì)地址,如果是這樣的話,需要對(duì)它做一些處理后才可以轉(zhuǎn)發(fā)


       

    處理HTTPS協(xié)議

    HttpClient提供了對(duì)SSL的支持,在使用SSL之前必須安裝JSSE。在Sun提供的1.4以后的版本中,JSSE已經(jīng)集成到JDK中,如果你使用的是JDK1.4以前的版本則必須安裝JSSE。JSSE不同的廠家有不同的實(shí)現(xiàn)。下面介紹怎么使用HttpClient來(lái)打開Https連接。這里有兩種方法可以打開https連接,第一種就是得到服務(wù)器頒發(fā)的證書,然后導(dǎo)入到本地的keystore中;另外一種辦法就是通過(guò)擴(kuò)展HttpClient的類來(lái)實(shí)現(xiàn)自動(dòng)接受證書。

    方法1,取得證書,并導(dǎo)入本地的keystore:

    • 安裝JSSE (如果你使用的JDK版本是1.4或者1.4以上就可以跳過(guò)這一步)。本文以IBM的JSSE為例子說(shuō)明。先到IBM網(wǎng)站上下載JSSE的安裝包。然后解壓開之后將ibmjsse.jar包拷貝到<java-home>\lib\ext\目錄下。
      
    • 取得并且導(dǎo)入證書。證書可以通過(guò)IE來(lái)獲得: 

      1. 用IE打開需要連接的https網(wǎng)址,會(huì)彈出如下對(duì)話框:

      2. 單擊"View Certificate",在彈出的對(duì)話框中選擇"Details",然后再單擊"Copy to File",根據(jù)提供的向?qū)纱L問(wèn)網(wǎng)頁(yè)的證書文件



      3. 向?qū)У谝徊剑瑲g迎界面,直接單擊"Next",

      4. 向?qū)У诙剑x擇導(dǎo)出的文件格式,默認(rèn),單擊"Next",



      5. 向?qū)У谌剑斎雽?dǎo)出的文件名,輸入后,單擊"Next",

      6. 向?qū)У谒牟剑瑔螕?Finish",完成向?qū)?/font>

      7. 最后彈出一個(gè)對(duì)話框,顯示導(dǎo)出成功


    • 用keytool工具把剛才導(dǎo)出的證書倒入本地keystore。Keytool命令在<java-home>\bin\下,打開命令行窗口,并到<java-home>\lib\security\目錄下,運(yùn)行下面的命令:

    • keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer
      

      其中參數(shù)alias后跟的值是當(dāng)前證書在keystore中的唯一標(biāo)識(shí)符,但是大小寫不區(qū)分;參數(shù)file后跟的是剛才通過(guò)IE導(dǎo)出的證書所在的路徑和文件名;如果你想刪除剛才導(dǎo)入到keystore的證書,可以用命令:

    • keytool -delete -keystore cacerts -storepass changeit -alias yourEntry1
       
    • 寫程序訪問(wèn)https地址。如果想測(cè)試是否能連上https,只需要稍改一下GetSample例子,把請(qǐng)求的目標(biāo)變成一個(gè)https地址。
      GetMethod getMethod = new GetMethod(https://www.yourdomain.com);

     

    運(yùn)行該程序可能出現(xiàn)的問(wèn)題:

    • 1. 拋出異常java.net.SocketException: Algorithm SSL not available。出現(xiàn)這個(gè)異常可能是因?yàn)闆](méi)有加JSSEProvider,如果用的是IBM的JSSE Provider,在程序中加入這樣的一行:
       if(Security.getProvider("com.ibm.jsse.IBMJSSEProvider") == null)
       Security.addProvider(new IBMJSSEProvider());

      

      或者也可以打開<java-home>\lib\security\java.security,在行

    • security.provider.1=sun.security.provider.Sun
      security.provider.2=com.ibm.crypto.provider.IBMJCE

    后面加入security.provider.3=com.ibm.jsse.IBMJSSEProvider

    2. 拋出異常java.net.SocketException: SSL implementation not available。出現(xiàn)這個(gè)異常可能是你沒(méi)有把ibmjsse.jar拷貝到<java-home>\lib\ext\目錄下。

    3. 拋出異常javax.net.ssl.SSLHandshakeException: unknown certificate。出現(xiàn)這個(gè)異常表明你的JSSE應(yīng)該已經(jīng)安裝正確,但是可能因?yàn)槟銢](méi)有把證書導(dǎo)入到當(dāng)前運(yùn)行JRE的keystore中,請(qǐng)按照前面介紹的步驟來(lái)導(dǎo)入你的證書。

    方法2,擴(kuò)展HttpClient類實(shí)現(xiàn)自動(dòng)接受證書

    因?yàn)檫@種方法自動(dòng)接收所有證書,因此存在一定的安全問(wèn)題,所以在使用這種方法前請(qǐng)仔細(xì)考慮您的系統(tǒng)的安全需求。具體的步驟如下:

    • 提供一個(gè)自定義的socket factory(test.MySecureProtocolSocketFactory)。這個(gè)自定義的類必須實(shí)現(xiàn)接口org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory,在實(shí)現(xiàn)接口的類中調(diào)用自定義的X509TrustManager(test.MyX509TrustManager),這兩個(gè)類可以在隨本文帶的附件中得到
      
    • 創(chuàng)建一個(gè)org.apache.commons.httpclient.protocol.Protocol的實(shí)例,指定協(xié)議名稱和默認(rèn)的端口號(hào)
      Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);
      
    • 注冊(cè)剛才創(chuàng)建的https協(xié)議對(duì)象 
      Protocol.registerProtocol("https ", myhttps);
    • 
    • 然后按照普通編程方式打開https的目標(biāo)地址,代碼請(qǐng)參見test.NoCertificationHttpsGetSample

    處理代理服務(wù)器

    HttpClient中使用代理服務(wù)器非常簡(jiǎn)單,調(diào)用HttpClient中setProxy方法就可以,方法的第一個(gè)參數(shù)是代理服務(wù)器地址,第二個(gè)參數(shù)是端口號(hào)。另外HttpClient也支持SOCKS代理。
    
    httpClient.getHostConfiguration().setProxy(hostName,port);

    結(jié)論 

    從上面的介紹中,可以知道HttpClient對(duì)http協(xié)議支持非常好,使用起來(lái)很簡(jiǎn)單,版本更新快,功能也很強(qiáng)大,具有足夠的靈活性和擴(kuò)展性。對(duì)于想在Java應(yīng)用中直接訪問(wèn)http資源的編程人員來(lái)說(shuō),HttpClient是一個(gè)不可多得的好工具。

    posted @ 2011-02-15 12:13 Jamie 閱讀(336) | 評(píng)論 (0)編輯 收藏

    test

    package client.test;

    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;

    import org.apache.commons.httpclient.HostConfiguration;
    import org.apache.commons.httpclient.HttpClient;
    import org.apache.commons.httpclient.HttpMethod;
    import org.apache.commons.httpclient.NameValuePair;
    import org.apache.commons.httpclient.methods.GetMethod;
    import org.apache.commons.httpclient.methods.PostMethod;
    import org.htmlparser.Node;
    import org.htmlparser.NodeFilter;
    import org.htmlparser.Parser;
    import org.htmlparser.filters.AndFilter;
    import org.htmlparser.filters.HasAttributeFilter;
    import org.htmlparser.filters.TagNameFilter;
    import org.htmlparser.nodes.TagNode;
    import org.htmlparser.util.NodeList;
    import org.htmlparser.util.ParserException;

    public class TIPOTest {

     private static String mainPageUrl = "http://twpat.tipo.gov.tw/twcgi/ttsweb?@0:0:1:twpat2@@"
       + Math.random();
     public static String strEncoding = "utf-8"; //strEncoding = "iso-8859-1";
     final static String userAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)";

     public static void main(String[] args) throws Exception {
    //  HttpClient client = new HttpClient();
    //  client.getHostConfiguration().setProxy("10.41.16.98", 808);
    //  client.getHostConfiguration().setHost(
    //    "http://twpat3.tipo.gov.tw/tipotwoc", 80, "http");

    //  String strLegalStatus = null;
      String mainPage = doGetMethod(mainPageUrl);

      String searchPageUrl = parserMainPage(mainPage);

      String searchPage = doGetMethod(searchPageUrl);

      String queryPageUrl = getQueryPageUrl(searchPage);

      String queryPage = doGetMethod(queryPageUrl);

      String searchResultUrl = parserPageForPostURL(queryPage);
      Map parameterMap = parseParameters(queryPage);

      System.out.println("searchResultUrl : " + searchResultUrl);

      String response = getResultPage(searchResultUrl, "087121847",
        parameterMap);

      // HttpMethod method = getPostMethod(); // 使用 POST 方式提交數(shù)據(jù)
      // // HttpMethod method = getGetMethod(); // 使用 GET 方式提交數(shù)據(jù)
      // client.executeMethod(method); // 打印服務(wù)器返回的狀態(tài)
      // System.out.println(method.getStatusLine()); // 打印結(jié)果頁(yè)面
      // String response = new
      // String(method.getResponseBodyAsString().getBytes(
      // "8859_1"));

      // 打印返回的信息
      System.out.println(response);
      // 釋放連接
      // method.releaseConnection();
     }

     private static String doGetMethod(String url) throws Exception {
      try {
       HttpClient httpClient = new HttpClient();
       HostConfiguration hc = httpClient.getHostConfiguration();

       hc.setProxy("10.41.16.98", 808);
       httpClient.getState().setAuthenticationPreemptive(true);

       GetMethod getMethod = new GetMethod(url);

       getMethod.setRequestCharSet(strEncoding);
       getMethod.setResponseCharSet(strEncoding);
       getMethod.setRequestHeader("User-Agent", userAgent);
       getMethod.setTimeout(1000 * 60 * 2);
       int StatusCode = httpClient.executeMethod(getMethod);
       if (StatusCode >= 400) {
        getMethod.getConnection().close();
        throw new Exception("Can't get information.");
       }
       String str = getMethod.getResponseBodyAsString();
       getMethod.releaseConnection();

       writeStrToTxt(str);// wuwen add for test

       return str;
      } catch (Exception e) {
       e.printStackTrace();
       throw e;
      }
     }

     static int i = 1;

     // wuwen add for test
     public static void writeStrToTxt(String str) {
      i++;
      BufferedWriter output;
      try {
       output = new BufferedWriter(new FileWriter(
         "C:\\Documents and Settings\\F3223114\\桌面\\" + i + ".txt"));

       output.write(str);
       output.close();

      } catch (IOException e) {
       e.printStackTrace();
      }
     }

     private static String parserMainPage(String body) {
      String parserSearchUrl = "";
      /*
       * String regEx = "href=(.+?)\\s*class=menu"; Pattern pattern =
       * Pattern.compile(regEx, Pattern.CASE_INSENSITIVE); Matcher matcher =
       * pattern.matcher(body); while (matcher.find()) { if
       * (matcher.group(1).contains(":80:::0")) { parserSearchUrl =
       * matcher.group(1); } }
       */
      int i = body.indexOf("http");
      if (i != -1) {
       parserSearchUrl = body.substring(i, body.indexOf(">", i));
      }
      return parserSearchUrl;
     }

     public String getMidString(String sInput, String sStartTag, String sEndTag) {
      int i, j = -1;
      if ((i = sInput.indexOf(sStartTag)) < 0) {
       return null;
      } else {
       if ((j = sInput.indexOf(sEndTag, i + sStartTag.length())) < 0) {
        return null;
       } else {
        if (i + sStartTag.length() == j) {
         return null;
        } else {
         return sInput.substring(i + sStartTag.length(), j);
        }
       }
      }
     }

     private static String doPostMethod(String url, NameValuePair[] nameValuePair)
       throws Exception {
      try {
       HttpClient httpClient = new HttpClient();
       HostConfiguration hc = httpClient.getHostConfiguration();
       hc.setProxy("10.41.16.98", 808);
       httpClient.getState().setAuthenticationPreemptive(true);

       PostMethod postMethod = new PostMethod(url);
       postMethod.setRequestCharSet(strEncoding);
       postMethod.setResponseCharSet(strEncoding);
       postMethod.setRequestHeader("User-Agent", userAgent);
       postMethod.setTimeout(1000 * 60 * 2);
       postMethod.setRequestBody(nameValuePair);
       int StatusCode = httpClient.executeMethod(postMethod);
       if (StatusCode >= 400) {
        postMethod.getConnection().close();
        throw new Exception("Can't get information.");
       }
       String str = postMethod.getResponseBodyAsString();

       postMethod.releaseConnection();
       return str;
      } catch (Exception e) {
       e.printStackTrace();
       throw e;
      }
     }

     // modify by zhuoluo 2008.12.09
     private static String getResultPage(String url, String strAppNo,
       Map parameterMap) throws Exception {
      try {
       NameValuePair _0_1_T = new NameValuePair("@_0_1_T", "T_UID");
       _0_1_T.setHeadNeedEncode(false);
       NameValuePair _0_1_T_1 = new NameValuePair("_0_1_T", "");
       _0_1_T_1.setHeadNeedEncode(false);
       NameValuePair _0_2_P = new NameValuePair("@_0_2_P", "P_PWD");
       _0_2_P.setHeadNeedEncode(false);
       NameValuePair _0_2_P_1 = new NameValuePair("_0_2_P", "");
       _0_2_P_1.setHeadNeedEncode(false);
       NameValuePair _20_0_T = new NameValuePair("@_20_0_T", "T_AN");
       _20_0_T.setHeadNeedEncode(false);
       NameValuePair appNo = new NameValuePair("_20_0_T", strAppNo);
       appNo.setHeadNeedEncode(false);
       NameValuePair _20_1_K = new NameValuePair("@_20_1_K", "K_NE");
       _20_1_K.setHeadNeedEncode(false);
       NameValuePair _20_1_K_1 = new NameValuePair("_20_1_K", "");
       _20_1_K_1.setHeadNeedEncode(false);
       NameValuePair JPAGE = new NameValuePair("JPAGE", "");
       JPAGE.setHeadNeedEncode(false);

       NameValuePair INFO = new NameValuePair("INFO", parameterMap.get(
         "INFO").toString());
       INFO.setHeadNeedEncode(false);

    //   NameValuePair x = new NameValuePair("_IMG_%E6%AA%A2%E7%B4%A2.x",
    //     "39");
    //   x.setHeadNeedEncode(false);
    //   NameValuePair y = new NameValuePair("_IMG_%E6%AA%A2%E7%B4%A2.y",
    //     "10");
    //   y.setHeadNeedEncode(false);
       NameValuePair x = new NameValuePair("_IMG_%E6%AA%A2%E7%B4%A2%25z.x",
       "39");
       x.setHeadNeedEncode(false);
       NameValuePair y = new NameValuePair("_IMG_%E6%AA%A2%E7%B4%A2%25z.y",
       "10");
       y.setHeadNeedEncode(false);

       NameValuePair[] nameValuePair = new NameValuePair[] { _0_1_T,
         _0_1_T_1, _0_2_P, _0_2_P_1, _20_0_T, appNo, _20_1_K,
         _20_1_K_1, x, y , INFO };
    //   NameValuePair[] nameValuePair = new NameValuePair[] { _0_1_T,
    //     _0_1_T_1, _0_2_P, _0_2_P_1, _20_0_T, appNo, _20_1_K,
    //     _20_1_K_1, JPAGE, INFO };//x, y ,
       String str = doPostMethod(url, nameValuePair);

       writeStrToTxt(str);// wuwen add for test

       return str;
      } catch (Exception e) {
       e.printStackTrace();
       throw e;
      }
     }

     private static String getQueryPageUrl(String body) {
      Parser parser = Parser.createParser(body, "utf-8");
      NodeFilter filter_constellation_summart = new AndFilter(
        (new TagNameFilter("a")), (new HasAttributeFilter("class",
          "menu")));
      NodeList nodeList = null;
      String href = "";
      try {
       nodeList = parser
         .extractAllNodesThatMatch(filter_constellation_summart);
       Node node = null;
       node = nodeList.elementAt(3);
       href = ((TagNode) node).getAttribute("href");
      } catch (ParserException ex) {
      }

      return href;
     }

     private static String parserPageForPostURL(String body)
       throws ParserException {
      String searchResultUrl = "";
      NodeFilter tagFilter = new TagNameFilter("FORM");
      Parser parser = Parser.createParser(body, "UTF-8");
      NodeList list = parser.extractAllNodesThatMatch(tagFilter);
      for (int i = 0; i < list.size(); i++) {
       Node node = list.elementAt(i);
       if (node instanceof TagNode) {
        String methodValue = ((TagNode) node).getAttribute("METHOD");
        if (methodValue != null) {
         String actionPath = ((TagNode) node).getAttribute("ACTION");
         searchResultUrl = actionPath;
        }
       }
      }
      return searchResultUrl;
     }

     private static Map<String, String> parseParameters(String pageBody)
       throws ParserException {
      Map<String, String> parameterMap = new HashMap<String, String>();
      NodeFilter tagFilter = new TagNameFilter("input");
      Parser parser = Parser.createParser(pageBody, "UTF-8");
      NodeList list = parser.extractAllNodesThatMatch(tagFilter);
      for (int i = 0; i < list.size(); i++) {
       Node node = list.elementAt(i);
       if (node instanceof TagNode) {
        String nodeName = ((TagNode) node).getAttribute("name");
        String nodeValue = ((TagNode) node).getAttribute("value");

        if (nodeName != null) {
         if (nodeName.equals("INFO")) {
          if (nodeValue == null) {
           nodeValue = "";
          }
          parameterMap.put(nodeName, nodeValue);
         }
        }
       }
      }
      return parameterMap;
     }
    }

    posted @ 2011-01-11 17:42 Jamie 閱讀(249) | 評(píng)論 (0)編輯 收藏

    TRUNC函數(shù)的用法

     

    TRUNC函數(shù)用于對(duì)值進(jìn)行截?cái)唷?/span>

    用法有兩種:TRUNC(NUMBER)表示截?cái)鄶?shù)字,TRUNC(date)表示截?cái)嗳掌凇?/span>

    (1)截?cái)鄶?shù)字:

    格式:TRUNC(n1,n2),n1表示被截?cái)嗟臄?shù)字,n2表示要截?cái)嗟侥且晃弧2可以是負(fù)數(shù),表示截?cái)嘈?shù)點(diǎn)前。注意,TRUNC截?cái)嗖皇撬纳嵛迦搿?/span>

    SQL> select TRUNC(15.79) from dual;

    TRUNC(15.79)
    ------------
              15

    SQL> select TRUNC(15.79,1) from dual;

    TRUNC(15.79,1)
    --------------
              15.7

    SQL> select trunc(15.79,-1) from dual;

    TRUNC(15.79,-1)
    ---------------
                 10

    (2)截?cái)嗳掌冢?/span>

    先執(zhí)行命令:alter session set nls_date_format='yyyy-mm-dd hh24:mi:hh';

    截取今天:

    SQL> select sysdate,trunc(sysdate,'dd') from dual;

    SYSDATE             TRUNC(SYSDATE,'DD')
    ------------------- -------------------
    2009-03-24 21:31:17 2009-03-24 00:00:00

    截取本周第一天:

    SQL> select sysdate,trunc(sysdate,'d') from dual;

    SYSDATE             TRUNC(SYSDATE,'D')
    ------------------- -------------------
    2009-03-24 21:29:32 2009-03-22 00:00:00

    截取本月第一天:

    SQL> select sysdate,trunc(sysdate,'mm') from dual;

    SYSDATE             TRUNC(SYSDATE,'MM')
    ------------------- -------------------
    2009-03-24 21:30:30 2009-03-01 00:00:00

    截取本年第一天:

    SQL> select sysdate,trunc(sysdate,'y') from dual;

    SYSDATE             TRUNC(SYSDATE,'Y')
    ------------------- -------------------
    2009-03-24 21:31:57 2009-01-01 00:00:00

    截取到小時(shí):

    SQL> select sysdate,trunc(sysdate,'hh') from dual;

    SYSDATE             TRUNC(SYSDATE,'HH')
    ------------------- -------------------
    2009-03-24 21:32:59 2009-03-24 21:00:00

    截取到分鐘:

    SQL> select sysdate,trunc(sysdate,'mi') from dual;

    SYSDATE             TRUNC(SYSDATE,'MI')
    ------------------- -------------------
    2009-03-24 21:33:32 2009-03-24 21:33:00


    獲取上月第一天:
    SQL> select TRUNC(add_months(SYSDATE,-1),'MM') from dual



    posted @ 2010-12-21 14:55 Jamie 閱讀(23726) | 評(píng)論 (0)編輯 收藏

    RMI原理及實(shí)現(xiàn)

    RMI原理及實(shí)現(xiàn)
    簡(jiǎn)介
      RMI是遠(yuǎn)程方法調(diào)用的簡(jiǎn)稱,象其名稱暗示的那樣,它能夠幫助我們查找并執(zhí)行遠(yuǎn)程對(duì)象的方法。通俗地說(shuō),遠(yuǎn)程調(diào)用就象將一個(gè)class放在A機(jī)器上,然后在B機(jī)器中調(diào)用這

    個(gè)class的方法。
      我個(gè)人認(rèn)為,盡管RMI不是唯一的企業(yè)級(jí)遠(yuǎn)程對(duì)象訪問(wèn)方案,但它卻是最容易實(shí)現(xiàn)的。與能夠使不同編程語(yǔ)言開發(fā)的CORBA不同的是,RMI是一種純Java解決方案。在RMI

    中,程序的所有部分都由Java編寫。
      在看本篇文章時(shí),我假定讀者都已經(jīng)具備了較扎實(shí)的Java基礎(chǔ)知識(shí),在這方面有欠缺的讀者請(qǐng)自行閱讀有關(guān)資料。
      概念
      我在前面已經(jīng)提到,RMI是一種遠(yuǎn)程方法調(diào)用機(jī)制,其過(guò)程對(duì)于最終用戶是透明的:在進(jìn)行現(xiàn)場(chǎng)演示時(shí),如果我不說(shuō)它使用了RNI,其他人不可能知道調(diào)用的方法存儲(chǔ)在其他

    機(jī)器上。當(dāng)然了,二臺(tái)機(jī)器上必須都安裝有Java虛擬機(jī)(JVM)。
      其他機(jī)器需要調(diào)用的對(duì)象必須被導(dǎo)出到遠(yuǎn)程注冊(cè)服務(wù)器,這樣才能被其他機(jī)器調(diào)用。因此,如果機(jī)器A要調(diào)用機(jī)器B上的方法,則機(jī)器B必須將該對(duì)象導(dǎo)出到其遠(yuǎn)程注冊(cè)服務(wù)器

    。注冊(cè)服務(wù)器是服務(wù)器上運(yùn)行的一種服務(wù),它幫助客戶端遠(yuǎn)程地查找和訪問(wèn)服務(wù)器上的對(duì)象。一個(gè)對(duì)象只有導(dǎo)出來(lái)后,然后才能實(shí)現(xiàn)RMI包中的遠(yuǎn)程接口。例如,如果想使機(jī)器A

    中的Xyz對(duì)象能夠被遠(yuǎn)程調(diào)用,它就必須實(shí)現(xiàn)遠(yuǎn)程接口。
      RMI需要使用占位程序和框架,占位程序在客戶端,框架在服務(wù)器端。在調(diào)用遠(yuǎn)程方法時(shí),我們無(wú)需直接面對(duì)存儲(chǔ)有該方法的機(jī)器。
      在進(jìn)行數(shù)據(jù)通訊前,還必須做一些準(zhǔn)備工作。占位程序就象客戶端機(jī)器上的一個(gè)本機(jī)對(duì)象,它就象服務(wù)器上的對(duì)象的代理,向客戶端提供能夠被服務(wù)器調(diào)用的方法。然

    后,Stub就會(huì)向服務(wù)器端的Skeleton發(fā)送方法調(diào)用,Skeleton就會(huì)在服務(wù)器端執(zhí)行接收到的方法。
      Stub和Skeleton之間通過(guò)遠(yuǎn)程調(diào)用層進(jìn)行相互通訊,遠(yuǎn)程調(diào)用層遵循TCP/IP協(xié)議收發(fā)數(shù)據(jù)。下面我們來(lái)大致了解一種稱為為“綁定”的技術(shù)。
      客戶端無(wú)論何時(shí)要調(diào)用服務(wù)器端的對(duì)象,你可曾想過(guò)他是如何告訴服務(wù)器他想創(chuàng)建什么樣的對(duì)象嗎?這正是“綁定”的的用武之地。在服務(wù)器端,我們將一個(gè)字符串變量與一個(gè)

    對(duì)象聯(lián)系在一起(可以通過(guò)方法來(lái)實(shí)現(xiàn)),客戶端通過(guò)將那個(gè)字符串傳遞給服務(wù)器來(lái)告訴服務(wù)器它要?jiǎng)?chuàng)建的對(duì)象,這樣服務(wù)器就可以準(zhǔn)確地知道客戶端需要使用哪一個(gè)對(duì)象了。所

    有這些字符串和對(duì)象都存儲(chǔ)在的遠(yuǎn)程注冊(cè)服務(wù)器中。
      在編程中需要解決的問(wèn)題
      在研究代碼之前,我們來(lái)看看必須編寫哪些代碼:
      遠(yuǎn)程對(duì)象:這個(gè)接口只定義了一個(gè)方法。我們應(yīng)當(dāng)明白的是,這個(gè)接口并非總是不包括方法的代碼而只包括方法的定義。遠(yuǎn)程對(duì)象包含要導(dǎo)出的每個(gè)方法的定義,它還實(shí)

    現(xiàn)Java.rmi中的遠(yuǎn)程接口。
      遠(yuǎn)程對(duì)象實(shí)現(xiàn):這是一個(gè)實(shí)現(xiàn)遠(yuǎn)程對(duì)象的類。如果實(shí)現(xiàn)了遠(yuǎn)程對(duì)象,就能夠覆蓋該對(duì)象中的所有方法,因此,遠(yuǎn)程對(duì)象的實(shí)現(xiàn)類將真正包含我們希望導(dǎo)出的方法的代碼。
      遠(yuǎn)程服務(wù)器:這是一個(gè)作為服務(wù)器使用的類,它是相對(duì)于要訪問(wèn)遠(yuǎn)程方法的客戶端而言的。它存儲(chǔ)著綁定的字符串和對(duì)象。
      遠(yuǎn)程客戶端:這是一個(gè)幫助我們?cè)L問(wèn)遠(yuǎn)程方法提供幫助的類,它也是最終用戶。我們將使用查找和調(diào)用遠(yuǎn)程方法的方法在該類中調(diào)用遠(yuǎn)程方法。
      編程
      我們將首先編寫遠(yuǎn)程對(duì)象,并將代碼保存為名字為AddServer.Java的文件:
      import Java.rmi.*;
      public interface AddServer extends Remote {
      public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException;
      }
      我們來(lái)看看上面的代碼。首先,為了使用其內(nèi)容,我們導(dǎo)入rmi包。然后,我們創(chuàng)建一個(gè)擴(kuò)展了Java.rmi中遠(yuǎn)程接口的接口。所有的遠(yuǎn)程對(duì)象必須擴(kuò)展該遠(yuǎn)程接口,我們將該

    遠(yuǎn)程接口稱為AddServer。在該遠(yuǎn)程對(duì)象中,有一個(gè)名字為AddNumbers的方法,客戶端可以調(diào)用這一方法。我們必須記住的是,所有的遠(yuǎn)程方法都需要啟

    動(dòng)RemoteException方法,有錯(cuò)誤發(fā)生時(shí)就會(huì)調(diào)用該方法。
      下面我們開始編寫遠(yuǎn)程對(duì)象的實(shí)現(xiàn)。這是一個(gè)實(shí)現(xiàn)遠(yuǎn)程對(duì)象并包含有所有方法代碼的類,將下面的代碼保存為名字為AddServerImpl.Java的文件:
      import Java.rmi.*;
      public class AddServerImpl extends UnicastRemoteObject implements AddServer {
      public AddServerImpl() {
      super();
      }
      public int AddNumbers(int firstnumber,int secondnumber) throws RemoteException {
      return firstnumber + secondnumber;
      }
      }
      首先,我們導(dǎo)入rmi包,然后創(chuàng)建一個(gè)擴(kuò)展UnicastRemoteObject和實(shí)現(xiàn)創(chuàng)建的遠(yuǎn)程對(duì)象的類;其次,我們可以為類創(chuàng)建一個(gè)缺省的構(gòu)建器。我們還了解了AddNumbers方

    法的代碼,它啟動(dòng)RemoteException。這樣我們就覆蓋了創(chuàng)建的遠(yuǎn)程對(duì)象中的方法。AddNumbers方法的代碼非常好理解,它接受2個(gè)整型參數(shù),然后相加并返回它們的和。
      至此,我們已經(jīng)有了二個(gè)Java文件:遠(yuǎn)程對(duì)象和遠(yuǎn)程對(duì)象的實(shí)現(xiàn)。下面我們將使用Javac命令編譯這二個(gè)文件:
      編譯遠(yuǎn)程對(duì)象:
      C:\jdk\bin\Javac workingdir\AddServer.Java
      編譯遠(yuǎn)程對(duì)象實(shí)現(xiàn):
      C:\jdk\bin\Javac workingdir\AddServerImpl.Java 這樣,就會(huì)達(dá)到二個(gè)Java文件和二個(gè)類文件,下面我們將創(chuàng)建stub和skeleton。為了創(chuàng)建stub和skeleton文件,

    我們必須使用rmic編譯器編譯遠(yuǎn)程對(duì)象實(shí)現(xiàn)文件。
      用Rmic編譯遠(yuǎn)程對(duì)象實(shí)現(xiàn)文件:
      C:\jdk\bin\rmic workingdir\AddServerImpl.Java 然后,我們就會(huì)發(fā)現(xiàn)多了2個(gè)新建的類文件,它們分別是AddServerImpl_Stub.class

    和AddServerImpl_Skel.class 。
      The Coding (Contd.)
      我們已經(jīng)編譯了所有的源代碼,下面我們來(lái)創(chuàng)建客戶端和服務(wù)器端,將下面的代碼保存為名字為RmiServer.Java的文件:
      import Java.rmi.*;
      import Java.net.*;
      public class RmiServer {
      public static void main (String args[]) throws RemoteException, MalformedURLException {
      AddServerImpl add = new AddServerImpl();
      Naming.rebind("addnumbers",add);
      }
      }
      首先,我們導(dǎo)入Java.rmi包和Java.net包。另外,我們還使用throws從句捕獲任何異常。我們從對(duì)象中得出遠(yuǎn)程對(duì)象實(shí)現(xiàn),使用rebind方法將字符串a(chǎn)ddnumbers與該對(duì)

    象綁定。下面的例子顯示了綁定的含義:
      從現(xiàn)在開始,無(wú)論何時(shí)客戶端要調(diào)用遠(yuǎn)程對(duì)象,使用字符串a(chǎn)ddnumbers就可以實(shí)現(xiàn)。rebind方法有二個(gè)參數(shù):第一個(gè)參數(shù)是字符串變量,第二個(gè)參數(shù)是遠(yuǎn)程對(duì)象實(shí)現(xiàn)類的

    對(duì)象。
      下面我們來(lái)創(chuàng)建客戶端,將下面的代碼保存為名字為RmiClient.Java的文件:
      import Java.rmi.*;
      import Java.net.*;
      public class RmiClient {
      public static void main(String args[]) throws RemoteException, MalformedURLException {
      String url="rmi://127.0.0.1/addnumbers";
      AddServer add;
      add = (AddServer)Naming.lookup(url);
      int result = add.AddNumbers(10,5);
      System.out.println(result);
      }
      }
      首先,我們導(dǎo)入Java.rmi包和Java.net包,并使用throws從句捕獲所有必要的異常。然后通過(guò)利用Naming類中的靜態(tài)lookup方法從遠(yuǎn)程對(duì)象中得到一個(gè)對(duì)象。(這也是我

    們無(wú)需從Naming類中得到一個(gè)對(duì)象并調(diào)用它。而只使用類名字的原因。)
      lookup方法接受遠(yuǎn)程對(duì)象的完整的URL名字,該URL由完整的機(jī)器IP地址以及與對(duì)象綁定的字符串(也誻對(duì)象的綁定名)組成。在調(diào)用遠(yuǎn)程對(duì)象時(shí),我們使用了RMI協(xié)

    議。lookup方法向我們返回一個(gè)對(duì)象,在能夠使用它前,我們必須將它的數(shù)據(jù)類型轉(zhuǎn)換為與遠(yuǎn)程對(duì)象的數(shù)據(jù)類型一致。
      Since we have both our server and client source ready, let's compile them both:
      至此,我們已經(jīng)有了服務(wù)器端和客戶端的源代碼,下面我們來(lái)編譯這二個(gè)源文件:
      編譯遠(yuǎn)程服務(wù)器:
      C:\jdk\bin\Javac workingdir\RmiServer.Java
      編譯遠(yuǎn)程客戶端:
      C:\jdk\bin\Javac workingdir\RmiClient.Java
      在對(duì)我們的代碼進(jìn)行測(cè)試前,還必須首先啟動(dòng)RMI Registry。RMI Registry存儲(chǔ)有所有綁定的數(shù)據(jù),沒(méi)有它,RMI就不能正常地運(yùn)行!
      啟動(dòng)Rmi Registry服務(wù)器:
      C:\jdk\bin\start rmiregistry
      我們會(huì)注意到,這時(shí)會(huì)出現(xiàn)一個(gè)空白的DOS提示符窗口,這表明Rmi Registry服務(wù)器在運(yùn)行,注意不要關(guān)閉該窗口。然后,我們首先在一個(gè)DOS提示符窗口中運(yùn)行Rmi服務(wù)

    器,然后在另一個(gè)DOS提示符窗口中運(yùn)行Rmi客戶端。
      啟動(dòng)RMI服務(wù)器:
      C:\jdk\bin\Java workingdir\RmiServer
      啟動(dòng)RMI客戶端:
      C:\jdk\bin\Java workingdir\RmiClient
      如果一切正常,我們應(yīng)該能夠得到15這個(gè)輸出。我們向AddNumbers方法輸入10和5二個(gè)數(shù)字,該方法將這二者加起來(lái),并將其和15返回給我們。如果得到了15這個(gè)輸出,

    說(shuō)明我們已經(jīng)成功地執(zhí)行了一個(gè)遠(yuǎn)程方法。當(dāng)然,在這里,我們并沒(méi)有執(zhí)行真正意義上的遠(yuǎn)程方法,因?yàn)槲覀兊挠?jì)算機(jī)既是服務(wù)器,又是客戶機(jī)。如果有計(jì)算機(jī)網(wǎng)絡(luò),我們就可以

    方便地進(jìn)行執(zhí)行遠(yuǎn)程方法的試驗(yàn)了。

    posted @ 2010-12-18 15:57 Jamie 閱讀(2932) | 評(píng)論 (0)編輯 收藏

    設(shè)置JTable不可編輯

    將JTable的單元格設(shè)置為不可編輯,有兩種方法。
    一種是自己寫一個(gè)MyTable類繼承DefaultTableModel,重寫其中的isCellEditable方法;
    還有一種是在創(chuàng)建JTable對(duì)象時(shí), JTable treeTable = new JTable(tableModel){ public boolean isCellEditable(int row, int column) { return false; }};

    posted @ 2010-10-08 09:34 Jamie 閱讀(2451) | 評(píng)論 (0)編輯 收藏

    JTable

    一.創(chuàng)建表格控件的各種方式:
    1) 調(diào)用無(wú)參構(gòu)造函數(shù).
    JTable table = new JTable();
    2) 以表頭和表數(shù)據(jù)創(chuàng)建表格.
    Object[][] cellData = {{"row1-col1", "row1-col2"},{"row2-col1", "row2-col2"}};
    String[] columnNames = {"col1", "col2"};
       
    JTable table = new JTable(cellData, columnNames);
    3) 以表頭和表數(shù)據(jù)創(chuàng)建表格,并且讓表單元格不可改.
    String[] headers = { "表頭一", "表頭二", "表頭三" };
    Object[][] cellData = null; 
    DefaultTableModel model = new DefaultTableModel(cellData, headers) {
    public boolean isCellEditable(int row, int column) {
        return false;
    }
    };
    table = new JTable(model);
    
    二.對(duì)表格列的控制
    0)獲取JTable中特定單元格的位置
    table.addMouseListener(new MouseListener() {
            public void mouseClicked(MouseEvent e) {
                       int row = jt.rowAtPoint(e.getPoint());
                       int col = jt.columnAtPoint(e.getPoint());
    }
    });
       
    1) 設(shè)置列不可隨容器組件大小變化自動(dòng)調(diào)整寬度.
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    2) 限制某列的寬度.
    TableColumn firsetColumn = table.getColumnModel().getColumn(0);
    firsetColumn.setPreferredWidth(30);
    firsetColumn.setMaxWidth(30);
    firsetColumn.setMinWidth(30);
    3) 設(shè)置當(dāng)前列數(shù).
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    int count=5;
    tableModel.setColumnCount(count);
    4) 取得表格列數(shù)
    int cols = table.getColumnCount();
    5) 添加列
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    tableModel.addColumn("新列名");
    6) 刪除列
    table.removeColumn(table.getColumnModel().getColumn(columnIndex));// columnIndex是要?jiǎng)h除的列序號(hào)
    三.對(duì)表格行的控制
    1) 設(shè)置行高
    table.setRowHeight(20);
    2) 設(shè)置當(dāng)前航數(shù)
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    int n=5;
    tableModel.setRowCount(n);
    3) 取得表格行數(shù)
    int rows = table.getRowCount();
    4) 添加表格行
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    tableModel.addRow(new Object[]{"sitinspring", "35", "Boss"});
    5) 刪除表格行
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    model.removeRow(rowIndex);// rowIndex是要?jiǎng)h除的行序號(hào)
    四.存取表格單元格的數(shù)據(jù)
    1) 取單元格數(shù)據(jù)
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    String cellValue=(String) tableModel.getValueAt(row, column);// 取單元格數(shù)據(jù),row是行號(hào),column是列號(hào)
    2) 填充數(shù)據(jù)到表格.
    注:數(shù)據(jù)是Member類型的鏈表,Member類如下:
    public class Member{
        // 名稱
        private String name;
       
        // 年齡
        private String age;
       
        // 職務(wù)
        private String title;
    }
    填充數(shù)據(jù)的代碼:
    public void fillTable(List<Member> members){
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    tableModel.setRowCount(0);// 清除原有行
    // 填充數(shù)據(jù)
    for(Member member:members){
        String[] arr=new String[3];
        arr[0]=member.getName();
        arr[1]=member.getAge();
        arr[2]=member.getTitle();
       
        // 添加數(shù)據(jù)到表格
        tableModel.addRow(arr);
    }
    // 更新表格
    table.invalidate();
    }
    2) 取得表格中的數(shù)據(jù)
    public List<Member> getShowMembers(){
    List<Member> members=new ArrayList<Member>();
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    int rowCount=tableModel.getRowCount();
    for(int i=0;i<rowCount;i++){
        Member member=new Member();
       
        member.setName((String)tableModel.getValueAt(i, 0));// 取得第i行第一列的數(shù)據(jù)
        member.setAge((String)tableModel.getValueAt(i, 1));// 取得第i行第二列的數(shù)據(jù)
        member.setTitle((String)tableModel.getValueAt(i, 2));// 取得第i行第三列的數(shù)據(jù)
       
        members.add(member);
    }
    return members;
    }
    五.取得用戶所選的行
    1) 取得用戶所選的單行
    int selectRows=table.getSelectedRows().length;// 取得用戶所選行的行數(shù)
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    if(selectRows==1){
    int selectedRowIndex = table.getSelectedRow(); // 取得用戶所選單行
    .// 進(jìn)行相關(guān)處理
    }
    2) 取得用戶所選的多行
    int selectRows=table.getSelectedRows().length;// 取得用戶所選行的行數(shù)
    DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
    if(selectRows>1)
    int[] selRowIndexs=table.getSelectedRows();// 用戶所選行的序列
    for(int i=0;i<selRowIndexs.length;i++){
        // 用tableModel.getValueAt(row, column)取單元格數(shù)據(jù)
        String cellValue=(String) tableModel.getValueAt(i, 1);
    }
    }
    六.添加表格的事件處理
    view.getTable().addMouseListener(new MouseListener() {
    public void mousePressed(MouseEvent e) {
        // 鼠標(biāo)按下時(shí)的處理
    }
    public void mouseReleased(MouseEvent e) {
        // 鼠標(biāo)松開時(shí)的處理
    }
    public void mouseEntered(MouseEvent e) {
        // 鼠標(biāo)進(jìn)入表格時(shí)的處理
    }
    public void mouseExited(MouseEvent e) {
        // 鼠標(biāo)退出表格時(shí)的處理
    }
    public void mouseClicked(MouseEvent e) {
        // 鼠標(biāo)點(diǎn)擊時(shí)的處理
    }
    });

    posted @ 2010-10-08 08:37 Jamie 閱讀(298) | 評(píng)論 (0)編輯 收藏

    Java 獲得本月一日、本星期星期一、昨天的date對(duì)象的方法

    GregorianCalendar cal = new GregorianCalendar();
    Date now = new Date();
    cal.setTime(now);
    cal.setFirstDayOfWeek(GregorianCalendar.MONDAY);   // 設(shè)置一個(gè)星期的第一天為星期1,默認(rèn)是星期日

    SimpleDateFormat dateutil = new SimpleDateFormat("yyyy-MM-dd");
    System.out.println("now=" + dateutil.format(cal.getTime()));  // 今天

    cal.add(GregorianCalendar.DATE,- 1);
    System.out.println("now=" + dateutil.format(cal.getTime())); // 昨天       

    cal.set(GregorianCalendar.DAY_OF_WEEK,GregorianCalendar.MONDAY);
    System.out.println("now=" + dateutil.format(cal.getTime()));   // 本周1

    cal.set(GregorianCalendar.DAY_OF_MONTH,1);
    System.out.println("now=" + dateutil.format(cal.getTime())); // 本月1日在此鍵入內(nèi)容

    posted @ 2010-09-21 11:32 Jamie 閱讀(173) | 評(píng)論 (0)編輯 收藏

    主站蜘蛛池模板: 免费在线观看黄网| 精品97国产免费人成视频| 无人在线观看完整免费版视频| 亚洲视频在线观看网址| 3344永久在线观看视频免费首页 | 亚洲理论电影在线观看| 999zyz**站免费毛片| 亚洲精品午夜无码电影网| 怡红院免费全部视频在线视频| 亚洲国产精品无码专区影院| 美女视频黄的免费视频网页| 久久精品国产亚洲AV网站| 免费精品无码AV片在线观看| 亚洲黄色网站视频| 1000部拍拍拍18勿入免费视频软件| 亚洲视频一区在线观看| 我的小后妈韩剧在线看免费高清版 | 免费无码肉片在线观看| 亚洲欧美自偷自拍另类视| 日本特黄特色免费大片| 亚洲精品成a人在线观看夫| 国产一级特黄高清免费大片| 一级毛片在线免费播放| 亚洲精品国产字幕久久不卡| 一区二区免费视频| 亚洲国产日产无码精品| 日韩伦理片电影在线免费观看| 黄色网址免费在线| 亚洲中文字幕无码中文字在线| 午夜老司机永久免费看片| 综合自拍亚洲综合图不卡区| 啦啦啦高清视频在线观看免费| 亚洲国产成人久久精品大牛影视| 亚洲Av无码乱码在线播放| 中文字幕在线观看免费| 亚洲综合网美国十次| 女人被免费视频网站| 免费看黄网站在线看| 亚洲∧v久久久无码精品| 国产免费AV片在线播放唯爱网| 亚洲av色香蕉一区二区三区|