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

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

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

    posts - 97,  comments - 93,  trackbacks - 0
     
    /**
        *@ the titlt  about a Random example about choose 7 from 33
        *@ the auther Nicky (EN) QuQiang(CH)
        *@ the date   2006.9.1
    **/



    /** the rules

    //一等獎:選中6個正選號及特別號;

    //二等獎:選中5個正選號及特別號;

    //三等獎:選中5個正選號;

    //四等獎:選中4個正選號及特別號;

    //五等獎:選中4個正選號或選中3個正選號及特別號;

    //六等獎:選中3個正選號。

    **/

    import java.util.*;

    public class NotSameRandoml{
         private static String transform;
         private static String match="00";
         private static int special;


      //產生彩票主邏輯函數
       private static void Nicky(int[] guess){
          Random r = new Random();     //構造偽隨機生成器
          //某些映射實現可明確保證其順序,如 TreeMap 類;某些映射實現則不保證順序,如 HashMap 類
          Map map = new TreeMap();   //Map 接口的實現
          int n = 0;
          int nt = 1;
          String[] temps=new String[7];
          
          while(true){
              n = r.nextInt(33)+1; //產生1~33的隨機數
              //if( map.get(new Integer(n))!=null){
              //   nt = ((Integer)map.get(new Integer(n))).intValue();  
              //}
              //避免了產生的隨機數字重復
              if(map.containsValue(n)){
                continue;
              }
              map.put(new Integer(nt),new Integer(n));//將指定的值與此映射中的指定鍵相關聯
              if(map.size()==7){
                 break;
              }
              nt++;
          }
          
          Iterator it = map.keySet().iterator(); //返回此映射中包含的鍵的 set 視圖
          for(int i=0;it.hasNext();i++){
           Object o = it.next();
            // 為了更符合現實中33選7,數字為01。。。2位
           int temp=((Integer)map.get(o)).intValue();
           if(temp>=1&&temp<10){
               transform="0"+Integer.toString(temp);
               match=match+" "+transform;
               temps[i]=transform;
               if(((Integer)o).intValue()==7){
                       special=temp;
                       System.out.println(""+transform+"為產生的特別中獎中獎號碼");
                   }else  
                     System.out.println(""+transform+"為產生的第"+((Integer)o).intValue()+"個中獎號碼");
            }else{
            temps[i]=Integer.toString(temp);
            match=match+" "+temps[i];
            if(((Integer)o).intValue()==7){
               System.out.println(""+transform+"為產生的特別中獎中獎號碼");
            }else
            System.out.println(""+temp+"為產生的第"+((Integer)o).intValue()+"個中獎號碼");
           }
          }
          String creat=match.substring(3);
          System.out.println("所產生的中獎號碼串為:"+creat);
          //System.out.println("對產生的中獎號碼順序排序為:"+creats);
          Sort(temps);
          check(map,guess);
       }
       
       //實現排序,也可以調用方法,但是卻必須要解決Void問題
        private static void Sort(String[] temps) {
             for(int i=0;i<temps.length;i++){
              for(int j=i+1;j<temps.length;j++){
             if(Integer.parseInt(temps[i])>Integer.parseInt(temps[j])){
                String k;
                k=temps[i];temps[i]=temps[j];temps[j]=k;
             }
            }
          }
          System.out.println("對產生的中獎號碼順序排序為:");
          for(int i=0;i<temps.length;i++){
              System.out.print(temps[i]+" ");
          }
          System.out.println("\n");
        }
       
       
      //輸出結果類別  
       private static void check(Map map ,int[] guess){
            int flag=0;
             for(int i=0;i<guess.length-1;i++){
                if(map.containsValue(guess[i])){
                        flag++;
                    }
             }
             if(guess[guess.length-1]==special){
                flag=flag+10;
             }
             switch(flag){
                  case 16: System.out.println("恭喜您中一等獎");break;
                  case 15: System.out.println("恭喜您中二等獎");break;
                  case  5: System.out.println("恭喜您中三等獎");break;
                  case 14: System.out.println("恭喜您中四等獎");break;
                  case 13: System.out.println("恭喜您中五等獎");break;
                  case  4: System.out.println("恭喜您中五等獎");break;
                  case  3: System.out.println("恭喜您中六等獎");break;
                  default: System.out.println("謝謝參與,祝您下次中獎");
             }
       }
       
       
       
      //說明
     
       private static void usage(){
          System.out.println("Usage:java Randomol program [the number you guess for the lucky nums.]");
          System.out.println("\t And the nums. you must typed 7,else you will be cancel by the game rules");
          System.out.println("\t The first 6 nums is your basic nums.,the last one is your special num.");
          System.exit(0);
       }
       
       
      //主函數
       public static void main(String []args){
            if(args.length==0||args.length>7){
                  usage();
                }//帶入參數
                int[] guess=new int[7];
                for(int i=0;i<args.length;i++){
                   guess[i]=Integer.parseInt(args[i]);
                }
                //判斷所輸入的號碼是否相同
            List <Integer> ls= new ArrayList<Integer>();
            for(int i=0;i<guess.length;i++){
               if(ls.contains(guess[i])){
                  System.out.println("您所買的號碼不可以相同");
                  System.exit(0);
               }else  ls.add(guess[i]);
            }
            Nicky(guess);      
            System.exit(0);
       }
    }
    posted @ 2006-10-12 18:45 wqwqwqwqwq 閱讀(451) | 評論 (0)編輯 收藏
    呵呵 不知道寫的如何。但是總感覺,在UltraEdit下寫,還是很爽的,或許是因為學校辦公室的電腦內存太小的緣故吧。
     1 /**
     2  * @the author:Nicky(EN) QuQiang(CH)
     3  * @the data :2006.8.27
     4  **/
     5 // 當然本算法最好編制成兩到3個文件
     6 
     7 public class HalfSearch{
     8     private static int lengthValue;
     9     private static byte  flag=0;
    10     private static int SearchValue=0;
    11    
    12     //定義返回數組類型的方法  此方法給出的public權限
    13     public static int[] Sort(int[] b){
    14         for(int i=0;i<b.length;i++){
    15             for(int j=i+1;j<b.length;j++){
    16                 int temp;
    17                 if(b[i]>b[j]){
    18                     temp=b[i];b[i]=b[j];b[j]=temp;
    19                 }
    20             }
    21         }
    22         System.out.println("\u6309\u5e8f\u6392\u5217\u4e3a:");  //對應漢字為     按序排列為:
    23         for(int i=0;i<b.length;i++){
    24           System.out.println(b[i]);
    25         }                            //冒泡排序法排序  或直接使用JDK提供的sort()函數進行排列
    26         return b;
    27     }
    28 
    29     //折半查找
    30     private static int Half(int[] a){
    31         int m=a.length,k,n=1;
    32         System.out.println("\u5f53\u524d\u5171\u8f93\u5165"+m+"\u4e2a\u6570\u7b26"); //對應漢字為  "當前共輸入" 個數符
    33         int index=0;
    34         if(m==1){
    35            if(a[0]==SearchValue){
    36              flag=1;
    37              index=1;
    38            }
    39            else{
    40               flag=0;
    41               index=1;
    42            }
    43         }             //考慮到用戶除輸入查找數符外,只輸入一個數符,即n=m=1
    44         for(int i=1;;i++){
    45           if(n<m){
    46              index+=1;
    47              k=(n+m)/2;
    48              if(a[k-1]>SearchValue){
    49                  m=k-1;      //此時定義最大值為當前中間值的前一個值  //第 次查找未成功,當前值大于SearchValue
    50                  System.out.println("\u7b2c"+index+"\u6b21\u67e5\u627e\u672a\u6210\u529f\uff0c \u5f53\u524d\u503c\u5927\u4e8e"+SearchValue);//否則將9改為變量
    51              }else if(a[k-1]<SearchValue){
    52                  n=k+1;          //未找到,則在后半區間進行查找  //小于
    53                  System.out.println("\u7b2c"+index+"\u6b21\u67e5\u627e\u672a\u6210\u529f\uff0c \u5f53\u524d\u503c\u5c0f\u4e8e"+SearchValue);//否則將9改為變量
    54              }else{
    55                  System.out.println("\u67e5\u627e\u6210\u529f");  //查找成功
    56                  flag=1;
    57                  break;
    58              }
    59            }else break;
    60          }
    61         return index;
    62     }                      //也可以定義一個用戶需輸入的查找值
    63    
    64     //使用說明
    65    private static void usage(){
    66       System.out.println("Usage:java HalfSearch program [the number you search] [the array list you give]");
    67       System.out.println("\t [the number you search] the only number you want to use it to test this program");
    68       System.out.println("\t [the Array list you give] A array list may be it contains it may be not");
    69       System.exit(0);
    70    }
    71       
    72     //主函數的功能  傳入查找數組
    73     public static void main(String[] args){
    74         if(args.length==0||args.length==1){
    75             usage();
    76             System.exit(0);
    77         }
    78         SearchValue=Integer.parseInt(args[0]);
    79         lengthValue=args.length;
    80         int index=0;
    81         int[] TransArray=new int[args.length-1];
    82         for(int i=1;i<args.length;i++){
    83             TransArray[i-1]=Integer.parseInt(args[i]);
    84             System.out.println(TransArray[i-1]);
    85         }
    86         index=HalfSearch.Half(HalfSearch.Sort(TransArray));
    87         //輸出查詢結果
    88         switch(flag){
    89              //在本次折半查找中共經過  次查找,未成功   成功
    90             case 0: System.out.println("\u5728\u672c\u6b21\u6298\u534a\u67e5\u627e\u4e2d\u5171\u7ecf\u8fc7"+index+"\u6b21\u67e5\u627e,\u672a\u6210\u529f");break;
    91             case 1: System.out.println("\u5728\u672c\u6b21\u6298\u534a\u67e5\u627e\u4e2d\u5171\u7ecf\u8fc7"+index+"\u6b21\u67e5\u627e,\u6210\u529f");break;
    92         }
    93         System.exit(0);
    94     }
    95 }


    posted @ 2006-08-27 17:02 wqwqwqwqwq 閱讀(646) | 評論 (0)編輯 收藏
    前幾天參加了SUN在大連的暑期免費培訓,主要是介紹了Netbeans集成開發環境和jdk1.5、1.6的一些新的特性。原來很少使用netbeans 來作程序,即使它是sun的產品。主要是因為4.1以前的版本過于garbage.但是參加完這次培訓之后,對其很有信心。這次培訓之后,我對sun的了解更加進了一步。這次培訓的老師是李濤老師和葉亮老師,這兩位老師我還是很佩服的。雖然sun的中國研究院,沒有微軟的那么大的名氣,但是我感覺這個團體還是一個很令人敬佩和挑戰創新的團體。我們無法想象沒有IDE的java編程,雖然在原來的文章中我更鼓勵初學者使用文本編輯工具。
        對于J2EE的框架理念我感覺這次沒有進行深入的介紹,或與也是我感覺比較遺憾的一點了。
    下面給大家介紹一點JDK1.5種新引入的泛型:


    以下代碼摘自java.util包的List接口和Iterator接口的定義:

    public interface List<E> {
      void add(E x);
      Iterator<E> iterator();
    }
    public interface Iterator<E> {
      E next();
      boolean hasNext();
    }

    類型參數

    與尖括號有關的一些東西是JDK 5引入的新東西, 它們是List和Iterator接口的形式的類型參數(簡稱類型形參)聲明.
    而在對泛型聲明List進行調用時(例如: List<Integer>), 所有出現的類型形參(如
    E)的地方, 都會被實際的類型參數(簡稱類型實參, 如 Integer)所替換掉.

    雖然與C++中的模板機制在形式上很想像, 但必需注意, Java中的泛型聲明決不會在調用時被展成多份副本: 不論是在源碼級, 二進制級, 還是在磁盤或內存中, 都不會被展開!

    泛型聲明只會也只需編譯一次, 并生成一個類文件(class文件), 這一點跟普通的類或接口完全一樣.

    類型參數其實跟方法或構造器中所用的通常參數相類似. 一個方法中可以聲明它用以處理的形式的值參數, 相似地, 泛型聲明也有其形式的類型參數; 當方法被調用時, 實際參數會替換形式參數, 然后執行方法體, 同樣, 當泛型聲明被調用時, 實際的類型參數會替換掉形式的類型參數.

    關于命名約定的備注: 推薦使用精煉而簡明(如, 單個字符)的方式為形式的類型參數命名. 最好避免使用小寫字符, 以便與普通的類或接口的參數相區分開來. 許多宣傳品類型使用 E 表示其元素的類型形參.




    先看以下兩行代碼是否合法:
    List<String> ls = new ArrayList<String>(); // 1
    List<Object> lo = ls; // 2
    第一行沒問題, 關鍵在第二行代碼, 大多數人會認為, 一個String的List自然更是一個Object的List, 因此, 第2行沒問題.

    好, 接著看以下代碼:
    lo.add(new Object()); // 3
    String s = ls.get(0); // 4: 試圖將一個Object賦給一個String!

    可見, 通過別名lo, 我們能對ls, 一個String的列表, 進行數據操作(特別是插入一個Object), 從而導致ls不僅僅是容納了String對象! 這是Java編譯器不容許的! 編譯時, 第2行會報告一個編譯錯誤的.

    通常, 若Foo是Bar的一個子類型(子類或子接口), G是某個泛型聲明, 則G<Foo>并不是G<Bar>的一個子類型.

    這一點往往是最難以理解的, 因為它和通常的直觀相左. 在直觀的理解中, 我們實際上假定了集合是不會變動的, 但java語言中則非如此.




    假定要輸出一個集合中的所有元素. 以下分別是舊版本及新版本(JDK 1.5)中的寫法:

    void printCollection(Collection c) {
      Iterator i = c.iterator();
      for( k = 0; k < c.size(); k++) {
        System.out.println( i.next() );
    }}

    void printCollection(Collection<Object> c) {
      for(Object e : c) {
        System.out.println(e);
    }}

    問題在于, 新版本反而不如舊版本更有用些. 因為舊版本能使用各種類型的集合作為參數, 但新版本則只能使用Collection<Object>. 而正如上節看到的, Collection<Object>并不是其它各種集合的超類型(父類型).

    所有集合的超類型應該寫作: Collection<?>, 讀作: collection of unknown(未知集合), 即一個集合, 其元素類型可以與任何類型相匹配. 因此稱這種類型為通配類型.

    正確實現上述舊版本的代碼可以這么寫:
    void printCollection(Collection<?> c) {
      for(Object e : c) {
        System.out.println(e);
    }}

    這時, 可以用任意類型的集合來調用此方法. 注意在方法體中, 仍然從 c 中讀入元素并賦給了Object, 這是沒有錯誤的, 因此不論類型實參是何種集合, 它的元素都是object. 然而, 如果任意給它增加一個object則是不安全的:

    Collection<?> c = new ArrayList<String>();
    c.add(new Object()); // 編譯時的錯誤

    由于我們不知道c的元素類型是什么, 所以不能給它增加一個object. 方法add()接受一個類型E的參數, 而E與集合的元素類型相同. 當類型實參是?時, 它表示未知的類型, 我們傳遞給add的參數必須是這個未知類型的子類型. 不幸的是, 既然類型未知, 也就無法決定其子類型, 于是什么也不能作為其參數. 唯一的例外是null, 因為null是所有類型的一個成員.

    另一方面, 如果給了一個List<?>, 我們可以調用get()方法并使用其返回的元素. 雖然返回的元素類型是未知類型, 但它總歸是一個object, 因此將get()返回的元素賦給一個Object類型的變量, 或將其傳遞給一個可接受Object的參數都是安全的.

    posted @ 2006-08-05 14:36 wqwqwqwqwq 閱讀(205) | 評論 (0)編輯 收藏

    只對5以上的版本有效,官方網站上有的,不過很多人沒看到罷了

    Spicing Up Your NetBeans IDE 5.0 With Substance

     

     

    This tech tip shows you how you can spice up your NetBeans IDE 5.0's look and feel with color themes, custom button-shapes and watermarks (wallpapers) using Substance plug-in. To use Substance with IDE 4.1 or any other Swing-based application, refer to Spicing Up Your Swing GUI With Substance.

    IDE with beyonce watermark

    Preparations

    • The Substance Look and Feel NBM works with JDK 5.0+ in NetBeans IDE 5.0 (development version).
    • If you want to integrate a watermark into your Swing application, you need a suitable (wide) wallpaper image file. Download this aquamarine JPG from digitalblasphemy as a sample.
    • For some features, you need to know how to access your operating system's commandline

    To install the substance-netbeans plugin into NetBeans IDE 5.0,

    1. download substance-netbeans.nbm from Kirill's project page and save the NBM file to your home directory. For this tutorial, I am using version 2.1_02.
    2. To plug the module in, open NetBeans IDE, and choose Tools > Update Center from the menu. In the Update Wizard window, check the box next to Install Manually Downloaded Modules (.nbm files), and then click the Next button.
    3. In the next screen, click the Add Button and select the substance-netbeans NBM file you just downloaded, then click OK. The NBM file shows up in the list of modules to install. Click the Next button.
    4. Make sure the NBM is visible in the field labelled Include to Install, then click the Next button. If a license agreement comes up, click Accept and then Next to proceed.
    5. A screen with the download progress bar appears. Again click the Next button.
    6. Check the Include box next to the line saying "NetBeans-Substance". If you are asked whether you really want to install an unsigned module, click Yes to proceed.
    7. Click the Finish button. If you are told that the IDE must be restarted, check the box saying Restart the IDE and then click the OK button.
    8. After the IDE has restarted, look into the View menu: If you see four new menu items, Button Shapes, Colors, Themes, and Watermarks, the plugin was installed successfully.

    http://www.netbeans.org/kb/50/substance-look-and-feel.html#creating

    按著步驟作就行了,先要下載一個.nbm的插件。
    posted @ 2006-07-22 17:24 wqwqwqwqwq 閱讀(569) | 評論 (0)編輯 收藏

    在Java中,我們只要利用BigInteger類,可以完成同樣功能;這里也測試了異常以及Dialog的產生。

    開發環境:Windows Server 2003 Standard Edition SP1, J2SDK 1.5.0_06, Eclipse 3.1.2
    源代碼如下:

    //Factorial.java
    import java.math.BigInteger;
    import javax.swing.*;


    /**
     * 計算任意正整數的階乘
     * 
     *
     */
    public class Factorial {
     public static void main(String[] args) {
      BigInteger x = BigInteger.valueOf(1); //存儲結果
      int num = 1; //待計算的整數
      String s = null;
      boolean correct = false;
      do {
       try {
        s = JOptionPane.showInputDialog(null, "請輸入要計算的數(正整數):");
        if (s == null)
         break;
        else {
         num = Integer.parseInt(s);
         if (num < 0)
          throw new IllegalArgumentException();
         else correct = true;
        }  
       } catch (NumberFormatException e) {
        JOptionPane.showMessageDialog(null, "數據格式錯誤!");
        continue;
       } catch (IllegalArgumentException e) {
        JOptionPane.showMessageDialog(null,"請輸入一個正整數!");
        continue;
       }
       break;
      } while (true);
      if (correct == true) {
       for (int i = 1; i <= num; i++)
        x = x.multiply(BigInteger.valueOf(i));
       JTextArea textArea = new JTextArea(x.toString(), 5, 30);
       textArea.setEditable(false);
       textArea.setLineWrap(true);
       Object[] object = {num + " ! : ",new JScrollPane(textArea)};
       JDialog dialog = new JOptionPane(object).createDialog(null,"階乘的結果");
       dialog.setVisible(true);
      }
      System.exit(0);
     }
    }

     

    運行結果如下:

    posted @ 2006-07-22 17:21 wqwqwqwqwq 閱讀(2064) | 評論 (2)編輯 收藏

        通常我們學習一門語言的時候,第一個寫的程序是輸出"Hello,World!",C/C++/Java中的入口都是main方法。實際上,在Java中,即便沒有main方法,我們也可以輸出Hello,程序如下:

    /**
     * @(#)Hello.java
     * 沒有main方法,輸出Hello,World!
     * 本程序請直接用javac編譯,java解釋運行
     * 經測試,如果在Eclipse中試圖運行,默認情況下,會啟動失敗
     *
     * @version J2SDK 1.4.2_10-b03
     */
    public class Hello {
     static {
      System.out.println("Hello,World!");
      System.exit(0);  //!如果缺少這一句,會出現運行期異常
     }
    }

        假使我們為Hello類增加一個main方法,雖然它也是static的,但是靜態初始化塊會在main之前被執行。

    posted @ 2006-07-22 17:19 wqwqwqwqwq 閱讀(546) | 評論 (0)編輯 收藏
    一直以來都對AI(人工智能)頗感興趣,可惜都是些外層的皮毛,離入門的境界還遠得很。最近在看《程序員》雜志2003年的合訂本,突然發現了一個技術專題,就是Robocode,忙到網上下載了一個,初次嘗試,感覺很有趣,特此推薦。

        一、Robocode簡介:Robocode是一位IBM的工程師Mat Nelson用Java語言所創造的機器人戰斗仿真引擎。Robocode不是一個完整游戲,它是個半成品,你所做的就是為你的機器人坦克編寫智能程序, 讓它能夠移動、進攻、防御、躲避、開火。只用幾十行代碼,就能立刻創造出一個簡單但完整機器人,你可以立即將它裝入Robocode 引擎中,再從Robocode 自帶的那些水平不一的示例機器人中選取一個進行一番對戰,還可以在網上下載由其他程序員編寫的水平更高的機器人,與它們比試一下,看看自己的水平到底如 何。
        開發Robocode,也是一個極佳的學習Java 語言的過程。隨著你的機器人的”智力”水平的提高,你的編程能力也就跟著水漲船高了。


        二、如果您想了解更多的細節,請查看如下的資料:

        1.有關Robocode的詳細資料,請查看如下的pdf文檔,內含Robocode的詳細介紹、Robocode安裝、高水平機器人的代碼分析、高級瞄 準策略、Robocode內核分析等7篇文章,幫助你入門,全部資料來自《程序員》2003年合訂本配套光盤,請點擊這里:http://www.loujing.com/mywork/java/Robocode/RobocodeBrief.pdf,(首先請確保你計算機內安裝了pdf文檔閱讀器,可自Adobe的網站自由下載,http://www.chinese-s.adobe.com/products/acrobat/readstep2.html)。

        2.如果您需要了解Robocode更詳細的信息,可參看如下網站:
        Robocode在IBM的官方網站為:http://www.alphaworks.ibm.com/tech/robocode;另外,現在Robocode項目已經終止,成為開源項目,您可以從如下站點下載其源代碼:http://robocode.sourceforge.net/

        3.您可以自我的網站下載Robocode的1.0.6版本,下載地址為:http://www.loujing.com/mywork/java/Robocode/Robocode.rar,下載解壓后雙擊其中的install.bat即可安裝。當然,請首先確保您的機器里安裝了J2SE SDK(Java軟件開發包),如果您不知道如何設置Java運行環境,請參考本人的另一篇文章:ShowArticle.asp?ArticleID=31。

        4.如果您是在Eclipse里進行Robocode的開發,您可以參考我的這篇文章http://www.loujing.com/Article/ShowArticle.asp?ArticleID=33

        希望您在游戲中也能不斷提高自己的Java編程水平,新年快樂!
    posted @ 2006-07-22 17:18 wqwqwqwqwq 閱讀(1732) | 評論 (1)編輯 收藏

    /**
     * 程序運行當年的日歷,程序運行當日以*號表示
     */

    import java.util.*;

    public class CalendarTest {
     public static void main(String[] args) {
      GregorianCalendar d = new GregorianCalendar();
      int year = d.get(Calendar.YEAR);
      int month = d.get(Calendar.MONTH);
      int today = d.get(Calendar.DAY_OF_YEAR);
      d.set(d.get(Calendar.YEAR),0,1);                  //設置為當年1月1日(0表示1月)
      do {
       System.out.println(d.get(Calendar.MONTH) + 1 + "月");
       System.out.println("Sun Mon Tue Wed Thu Fri Sat"); //輸出月表頭
       month = d.get(Calendar.MONTH);                //取得月份    
       int weekday = d.get(Calendar.DAY_OF_WEEK);    //獲得當月1號,在一周中是星期幾
       for(int i = Calendar.SUNDAY; i < weekday; i++)//控制當月1號的起始位置
        System.out.print("    ");
       do {
        weekday = d.get(Calendar.DAY_OF_WEEK);
        if (d.get(Calendar.DAY_OF_MONTH) < 10)    //如果日期小于10,多輸出一個空格,以便對齊
         System.out.print(" ");
        System.out.print(d.get(Calendar.DAY_OF_MONTH));//輸出日期
        if (today == d.get(Calendar.DAY_OF_YEAR)) //如果是當日,則輸出一個*號
         System.out.print("* ");
        else
         System.out.print("  ");
        if (weekday == Calendar.SATURDAY)         //到達周六,則換行
         System.out.println();
        d.add(Calendar.DAY_OF_YEAR,1);            //日期累加
       } while (d.get(Calendar.MONTH) == month);     //如果還是當月,繼續循環
       System.out.println("\n");
      } while (d.get(Calendar.YEAR) == year);           //如果還是當年,繼續循環
     }
    }
    posted @ 2006-07-22 17:17 wqwqwqwqwq 閱讀(366) | 評論 (0)編輯 收藏
    動機:
    充分利用java陣營眾多的類庫

    工具:

    IKVM――把java bytecode 轉換成IL程序,并提供大部分J2SE 1.4類的.net實現(IKVM.GNU.Classpath.dll)

    winrar――提取jar,打包jar

    Java IDE(可選)――閱讀源代碼,瀏覽類之間的關系,我用的是eclipse

    反編譯工具(可選)――沒源代碼時用,主要也是瀏覽類與類之間的關系,java反編譯我用的是DJ Java Decompiler,.net用...
    posted @ 2006-05-24 09:15 wqwqwqwqwq 閱讀(445) | 評論 (0)編輯 收藏
    SWT
    Java語言的聲望和它在桌面應用程序(GUI程序)所取得的成就顯然極不相符,至今仍然很少能看到非常成功Java桌面程序。雖然有JBuilder, Netbean,JProbe等大型軟件作為代表,但這仍不能證明Java的GUI程序是成功的:它們的外觀總是和同一操作系統平臺下的其它軟件顯得格格 不入。對機器配置的需求也似乎永無止境,這使得它們只能被一些總是擁有當前最高性能PC的程序員們所容忍,或是那些不在乎金錢和時間的專業用戶所接受。對 絕大多數計算機使用者來說,AWT或SWING代表著怪異的界面和無法接受的速度。Standard Widget Toolkit(SWT)或許是Java這一噩夢的終結者,廣大Java程序員終于可以開發出高效率的GUI程序,它們擁有標準的外觀,幾乎沒有人能看出 你的程序是用Java寫出來的,更為重要的是,這些程序是跨平臺的。

    SWT本身僅僅是Eclipse組織為了開發Eclipse IDE環境所編寫的一組底層圖形界面 API?;蛟S是無心插柳,或是有意為之,至今為止,SWT無論是在性能和外觀上,都超越了SUN公司提供的AWT和SWING。目前Eclipse IDE已經開發到了2.1版本,SWT已經十分穩定。這里指的穩定應該包含兩層意思:

    一是指性能上的穩定,其中的關鍵是源于SWT的設計理念。SWT最大化了操作系統的圖形構件API,就是說只要操作系統提供了相應圖形的構件,那么 SWT只是簡單應用JNI技術調用它們,只有那些操作系統中不提供的構件,SWT才自己去做一個模擬的實現。可以看出SWT的性能上的穩定大多時候取決于 相應操作系統圖形構件的穩定性。

    另一個穩定是指SWT API包中的類、方法的名稱和結構已經少有改變,程序員不用擔心由于Eclipse組織開發進度很快(Eclipse IDE每天都會有一個Nightly版本的發布),而導致自己的程序代碼變化過大。從一個版本的SWT更新至另一版本,通常只需要簡單將SWT包換掉就可 以了。

    第一個SWT程序

    下面讓我們開始一個SWT程序。(注意:以下的例子和說明主要針對Windows平臺,其它的操作系統應該大同小異)。首先要在Eclipse安裝文 件中找到SWT包,Eclipse組織并不提供單獨的SWT包下載,必須下載完整的Eclipse開發環境才能得到SWT包。SWT是作為Eclipse 開發環境的一個插件形式存在,可以在${你的eclipse安裝路徑}\plugins路徑下的眾多子目錄下去搜索SWT.JAR文件,在找到的JAR文 件中包含了SWT全部的Java類文件。因為SWT應用了JNI技術,因此同時也要找到相對應的JNI本地化庫文件,由于版本和操作平臺的不同,本地化庫 文件的名稱會有些差別,比如SWT-WIN32-2116.DLL是Window平臺下Eclipse Build 2116的動態庫,而在Unix平臺相應版本的庫文件的擴展名應該是.so,等等。注意的是,Eclipse是一個開放源代碼的項目,因此你也可以在這些 目錄中找到SWT的源代碼,相信這會對開發很有幫助。下面是一段打開空窗口的代碼(只有main方法)。

    import com.e2one.example;
    public class OpenShell{
    public static void main(String [] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.open();
    // 開始事件處理循環,直到用戶關閉窗口
    while (!shell.isDisposed()) {
    if (!display.readAndDispatch())
    display.sleep();
    }
    display.dispose();
    }
    }

    確信在CLASSPATH中包括了SWT.JAR文件,先用Javac編譯例子程序。編譯無錯后可運行java -Djava.library.path=${你的SWT本地庫文件所在路徑} com.e2one.example.OpenShell,比如SWT-WIN32-2116.DLL件所在的路徑是C:\swtlib,運行的命令應該 是java -Djava.library.path=c:\swtlib com.e2one.example.OpenShell。成功運行后,系統會打開了一個空的窗口。

    剖析SWT API

    下面再讓我們進一步分析SWT API的組成。所有的SWT類都用org.eclipse.swt做為包的前綴,下面為了簡化說明,我們用*號代表前綴org.eclipse.swt, 比如*.widgets包,代表的是org.eclipse.swt.widgets包。

    我們最常用的圖形構件基本都被包括在*.widgets包中,比如Button,Combo,Text,Label,Sash,Table等等。其中 兩個最重要的構件當數Shell和Composite。Shell相當于應用程序的主窗口框架,上面的例子代碼中就是應用Shell構件打開一個空窗口。 Composite相當于SWING中的Panel對象,充當著構件容器的角色,當我們想在一個窗口中加入一些構件時,最好到使用Composite作為 其它構件的容器,然后再去*.layout包找出一種合適的布局方式。SWT對構件的布局也采用了SWING或AWT中Layout和Layout Data結合的方式,在*.layout包中可以找到四種Layout和與它們相對應的布局結構對象(Layout Data)。在*.custom包中,包含了對一些基本圖形構件的擴展,比如其中的CLabel,就是對標準Label構件的擴展,上面可以同時加入文字 和圖片,也可以加邊框。StyledText是Text構件的擴展,它提供了豐富的文本功能,比如對某段文字的背景色、前景色或字體的設置。在 *.custom包中也可找到一個新的StackLayout布局方式。

    SWT對用戶操作的響應,比如鼠標或鍵盤事件,也是采用了AWT和SWING中的Observer模式,在*.event包中可以找到事件監聽的 Listener接口和相應的事件對象,例如常用的鼠標事件監聽接口MouseListener,MouseMoveListener和 MouseTrackListener,及對應的事件對象MouseEvent。

    *.graphics包中可以找到針對圖片、光標、字體或繪圖的API。比如可通過Image類調用系統中不同類型的圖片文件。通過GC類實現對圖片、構件或顯示器的繪圖功能。

    對不同平臺,Eclipse還開發了一些富有針對性的API。例如,在Windows平臺,可以通過*.ole.win32包很容易的調用ole控件,這使Java程序內嵌IE瀏覽器或Word、Excel等程序成為可能!

    更復雜的程序

    下面讓我們展示一個比上面例子更加復雜一些的程序。這個程序擁有一個文本框和一個按鍵,當用戶點擊按鍵的時候,文本框顯示一句歡迎信息。

    為了文本框和按鍵有比較合理的大小和布局,這里采用了GradLayout布局方式。這種布局是SWT中最常用也是最強大的布局方式,幾乎所有的格式 都可能通過GradLayout去達到。下面的程序也涉及到了如何應用系統資源(Color),以及如何釋放系統資源。

    private void initShell(Shell shell) {
    //為Shell設置布局對象
    GridLayout gShellLay = new GridLayout();
    shell.setLayout(gShellLay);
    //構造一個Composite構件作為文本框和按鍵的容器
    Composite panel = new Composite(shell,SWT.NONE);
    //為Panel指定一個布局結構對象。
    這里讓Panel盡可能的占滿Shell,
    也就是全部應用程序窗口的空間。
    GridData gPanelData = new GridData(GridData.GRAB_HORIZONTAL| GridData.GRAB_VERTICAL|GridData.FILL_BOTH);
    panel.setLayoutData(gPanelData);
    //為Panel也設置一個布局對象。文本框和按鍵將按這個布局對象來顯示。
    GridLayout gPanelLay = new GridLayout();
    panel.setLayout(gPanelLay);
    //為Panel生成一個背景色
    final Color bkColor = new Color(Display.getCurrent(),200,0,200);
    panel.setBackground(bkColor);
    //生成文本框
    final Text text = new Text(panel,SWT.MULTI|SWT.WRAP);
    //為文本框指定一個布局結構對象,
    這里讓文本框盡可能的占滿Panel的空間。
    GridData gTextData = new GridData (GridData.GRAB_HORIZONTAL| GridData.GRAB_VERTICAL|GridData.FILL_BOTH);
    text.setLayoutData(gTextData);
    //生成按鍵
    Button butt = new Button(panel,SWT.PUSH);
    butt.setText("Push");
    //為按鍵指定鼠標事件
    butt.addMouseListener(new MouseAdapter(){
    public void mouseDown(MouseEvent e){
    //當用戶點擊按鍵的時候,顯示信息
    text.setText("Hello SWT");
    }
    });
    //當主窗口關閉時,會觸發DisposeListener。這里用來釋放Panel的背景色。
    shell.addDisposeListener(new DisposeListener(){
    public void widgetDisposed(DisposeEvent e) {
    bkColor.dispose();
    }
    });
    }

    把這段代碼中的方法initShell()加入到第一個打開空窗口的例子中,得到的是一段能成功運行的完整GUI應用程序。運行方法可參考第一個例子。  

    系統資源的管理

    在一個圖形化的操作系統中開發程序,都要調用系統中的資源,如圖片、字體、顏色等。通常這些資源都是有限的,程序員務必非常小心的使用這些資源:當不再使用它們時,就請盡快釋放,不然操作系統遲早會油盡燈枯,不得不重新啟動,更嚴重的會導致系統崩潰。
    SWT是用Java開發的,Java語言本身的一大優勢就是JVM的"垃圾回收機制",程序員通常不用理會變量的釋放,內存的回收等問題。那么對SWT而言,系統資源的操作是不是也是如此?答案是一個壞消息,一個好消息。

    壞消息是SWT并沒采用JVM的垃圾回收機制去處理操作系統的資源回收問題,一個關鍵的因素是因為JVM的垃圾回收機制是不可控的,也就是說程序員不 能知道,也不可能做到在某一時刻讓JVM回收資源!這對系統資源的處理是致命的,試想你的程序希望在一個循環語句中去查看數萬張圖片,常規的處理方式是每 次調入一張,查看,然后就立即釋放該圖片資源,而后在循環調入下一張圖片,這對操作系統而言,任何時刻程序占用的僅僅是一張圖片的資源。但如果這個過程完 全交給JVM去處理,也許會是在循環語句結束后,JVM才會去釋放圖片資源,其結果可能是你的程序還沒有運行結束,操作系統已經宕掉。

    但下面的好消息也許會讓這個壞消息變得無關緊要。對于SWT,只需了解兩條簡單的"黃金"法則就可以放心的使用系統資源!之所以稱為黃金法則,一是因 為少,只有兩條,二是因為它們出奇的簡單。第一條是"誰占用,誰釋放",第二條是"父構件被銷毀,子構件也同時被銷毀"。第一條原則是一個無任何例外的原 則,只要程序調用了系統資源類的構造函數,程序就應該關心在某一時刻要釋放這個系統資源。比如調用了

    Font font = new Font (display, "Courier", 10, SWT.NORMAL);

    那么就應該在不在需要這個Font的時候調用

    font.dispose();

    對于第二個原則,是指如果程序調用某一構件的dispose()方法,那么所有這個構件的子構件也會被自動調用dispose()方法而銷毀。通常這里指的子構件與父構件的關系是在調用構件的構造函數時形成的。比如,

    Shell shell = new Shell();
    Composite parent = new Composite(shell,SWT.NULL);
    Composite child = new Composite(parent,SWT.NULL);

    其中parent的父構件是shell,而shell則是程序的主窗口,所以沒有相應的父構件,同時parent又包括了child子構件。如果調用 shell.dispose()方法,應用第二條法則,那么parent和child構件的dispose()方法也會被SWT API自動調用,它們也隨之銷毀。

    線程問題

    在任何操作平臺的GUI系統中,對構件或一些圖形API的訪問操作都要被嚴格同步并串行化。例如,在一個圖形界面中的按鍵構件可被設成可用狀態 (enable)或禁用狀態(disable),正常的處理方式是,用戶對按鍵狀態設置操作都要被放入到GUI系統的事件處理隊列中(這意味著訪問操作被 串行化),然后依次處理(這意味著訪問操作被同步)。想象當按鍵可用狀態的設置函數還沒有執行結束的時候,程序就希望再設置該按鍵為禁用狀態,勢必會引起 沖突。實際上,這種操作在任何GUI系統都會觸發異常。

    Java語言本身就提供了多線程機制,這種機制對GUI編程來說是不利的,它不能保證圖形構件操作的同步與串行化。SWT采用了一種簡單而直接的方式 去適應本地GUI系統對線程的要求:在SWT中,通常存在一個被稱為"用戶線程"的唯一線程,只有在這個線程中才能調用對構件或某些圖形API的訪問操 作。如果在非用戶線程中程序直接調用這些訪問操作,那么SWTExcepiton異常會被拋出。但是SWT也在*.widget.Display類中提供 了兩個方法可以間接的在非用戶線程的進行圖形構件的訪問操作,這是通過的syncExec(Runnable)和asyncExec(Runnable) 這兩個方法去實現的。例如:

    //此時程序運行在一個非用戶線程中,并且希望在構件panel上加入一個按鍵。

    Display.getCurrent().asyncExec(new Runnable() {
    public void run() {
    Button butt = new Button(panel,SWT.PUSH);
    butt.setText("Push");
    }
    });

    方法syncExec()和asyncExec()的區別在于前者要在指定的線程執行結束后才返回,而后者則無論指定的線程是否執行都會立即返回到當前線程。

    SWT的擴展:JFace

    JFace與SWT的關系好比Microsoft的MFC與SDK的關系,JFace是基于SWT開發,其API比SWT更加易于使用,但功能卻沒SWT來的直接。比如下面的代碼應用JFace中的MessageDialog打開一個警告對話框:

    MessageDialog.openWarning(parent,"Warning","Warning message");

    如果只用SWT完成以上功能,語句不會少于30行!

    JFace原本是為更加方便的使用SWT而編寫的一組API,其主要目的是為了開發Eclipse IDE環境,而不是為了應用到其它的獨立應用程序。因此在Eclipse 2.1版本之前,很難將JFace API完整的從Eclipse的內核API中剝離出來,總是要多多少少導入一些非JFace以外的Eclipse核心代碼類或接口才能得到一個沒有任何編 譯錯誤的JFace開發包。但目前Eclipse組織似乎已經逐漸意識到了JFace在開發獨立應用程序起到的重要作用,在正在開發的2.1版本中, JFace也開始變成了和SWT一樣的完整獨立的開發包,只是這個開發包還在變動中(筆者寫本文時,應用的Eclipse2.1M3版本)。JFace開 發包的包前綴是以org.eclipse.jface開頭。JAR包和源代碼也和SWT一樣,也在${你的eclipse安裝路徑}\plugins路徑 下去找。

    對開發人員來說,在開發一個圖形構件的時候,比較好的方式是先到JFace包去找一找,看是不是有更簡潔的實現方法,如果沒有再用SWT包去自己實 現。比如JFace為對話框提供了很好的支持,除了各種類型的對話框(比如上面用的MessageDialog,或是帶有Title欄的對話框),如要實 現一個自定義的對話框也最好從JFace中的Dialog類繼承,而不是從SWT中的*.widget.Dialog繼承。

    應用JFace中的Preference包中的類很容易為自己的軟件做出一個很專業的配置對話框。對于Tree、Table等圖形構件,它們在顯示的 同時也要和數據關聯,例如Table中顯示的數據,在JFace中的View包中為此類構件提供了Model-View方式的編程方法,這種方法使顯示與 數據分開,更加利于開發與維護。JFace中提供最多的功能就是對文本內容的處理。可以在org.eclipse.jface.text.*包中找到數十 個與文本處理相關類。

    與應用程序更近一步

    Java程序通常是以class文件的方式發布的,運行class需要JRE或JDK的支持。這又是Java GUI程序的另一個致命的弱點,想象對一個面向廣大用戶的應用程序來說,無論你的程序功能有多簡單,或是你的代碼十分的精簡,你都不得不讓用戶去下載一個 7、8M的JRE,那是多么令人沮喪的一件事。而且對程序員來說,Class通常意味著源代碼的暴露,反編譯的工具讓那些居心叵測的人輕易得到你的源代 碼。雖然有很多對Class的加密方法,但那總是以犧牲性能為代價的。好在我們還有其它的方式可用:把Class編譯成exe文件!

    通過SWT開發包,簡單、跨平臺、可靠等這些Java語言本身所具有的優點正漸漸融合到圖形界面的應用程序開發中去。因此,我相信Java語言的另一扇成功之門正在逐漸打開。Java語言的聲望和它在桌面應用程序(GUI程序)所取得的成就顯然極不相符,至今仍然很少能看到非常成功Java桌面程序。雖然有JBuilder, Netbean,JProbe等大型軟件作為代表,但這仍不能證明Java的GUI程序是成功的:它們的外觀總是和同一操作系統平臺下的其它軟件顯得格格 不入。對機器配置的需求也似乎永無止境,這使得它們只能被一些總是擁有當前最高性能PC的程序員們所容忍,或是那些不在乎金錢和時間的專業用戶所接受。對 絕大多數計算機使用者來說,AWT或SWING代表著怪異的界面和無法接受的速度。Standard Widget Toolkit(SWT)或許是Java這一噩夢的終結者,廣大Java程序員終于可以開發出高效率的GUI程序,它們擁有標準的外觀,幾乎沒有人能看出 你的程序是用Java寫出來的,更為重要的是,這些程序是跨平臺的。

    SWT本身僅僅是Eclipse組織為了開發Eclipse IDE環境所編寫的一組底層圖形界面 API?;蛟S是無心插柳,或是有意為之,至今為止,SWT無論是在性能和外觀上,都超越了SUN公司提供的AWT和SWING。目前Eclipse IDE已經開發到了2.1版本,SWT已經十分穩定。這里指的穩定應該包含兩層意思:

    一是指性能上的穩定,其中的關鍵是源于SWT的設計理念。SWT最大化了操作系統的圖形構件API,就是說只要操作系統提供了相應圖形的構件,那么 SWT只是簡單應用JNI技術調用它們,只有那些操作系統中不提供的構件,SWT才自己去做一個模擬的實現??梢钥闯鯯WT的性能上的穩定大多時候取決于 相應操作系統圖形構件的穩定性。

    另一個穩定是指SWT API包中的類、方法的名稱和結構已經少有改變,程序員不用擔心由于Eclipse組織開發進度很快(Eclipse IDE每天都會有一個Nightly版本的發布),而導致自己的程序代碼變化過大。從一個版本的SWT更新至另一版本,通常只需要簡單將SWT包換掉就可 以了。

    第一個SWT程序

    下面讓我們開始一個SWT程序。(注意:以下的例子和說明主要針對Windows平臺,其它的操作系統應該大同小異)。首先要在Eclipse安裝文 件中找到SWT包,Eclipse組織并不提供單獨的SWT包下載,必須下載完整的Eclipse開發環境才能得到SWT包。SWT是作為Eclipse 開發環境的一個插件形式存在,可以在${你的eclipse安裝路徑}\plugins路徑下的眾多子目錄下去搜索SWT.JAR文件,在找到的JAR文 件中包含了SWT全部的Java類文件。因為SWT應用了JNI技術,因此同時也要找到相對應的JNI本地化庫文件,由于版本和操作平臺的不同,本地化庫 文件的名稱會有些差別,比如SWT-WIN32-2116.DLL是Window平臺下Eclipse Build 2116的動態庫,而在Unix平臺相應版本的庫文件的擴展名應該是.so,等等。注意的是,Eclipse是一個開放源代碼的項目,因此你也可以在這些 目錄中找到SWT的源代碼,相信這會對開發很有幫助。下面是一段打開空窗口的代碼(只有main方法)。

    import com.e2one.example;
    public class OpenShell{
    public static void main(String [] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.open();
    // 開始事件處理循環,直到用戶關閉窗口
    while (!shell.isDisposed()) {
    if (!display.readAndDispatch())
    display.sleep();
    }
    display.dispose();
    }
    }

    確信在CLASSPATH中包括了SWT.JAR文件,先用Javac編譯例子程序。編譯無錯后可運行java -Djava.library.path=${你的SWT本地庫文件所在路徑} com.e2one.example.OpenShell,比如SWT-WIN32-2116.DLL件所在的路徑是C:\swtlib,運行的命令應該 是java -Djava.library.path=c:\swtlib com.e2one.example.OpenShell。成功運行后,系統會打開了一個空的窗口。

    剖析SWT API

    下面再讓我們進一步分析SWT API的組成。所有的SWT類都用org.eclipse.swt做為包的前綴,下面為了簡化說明,我們用*號代表前綴org.eclipse.swt, 比如*.widgets包,代表的是org.eclipse.swt.widgets包。

    我們最常用的圖形構件基本都被包括在*.widgets包中,比如Button,Combo,Text,Label,Sash,Table等等。其中 兩個最重要的構件當數Shell和Composite。Shell相當于應用程序的主窗口框架,上面的例子代碼中就是應用Shell構件打開一個空窗口。 Composite相當于SWING中的Panel對象,充當著構件容器的角色,當我們想在一個窗口中加入一些構件時,最好到使用Composite作為 其它構件的容器,然后再去*.layout包找出一種合適的布局方式。SWT對構件的布局也采用了SWING或AWT中Layout和Layout Data結合的方式,在*.layout包中可以找到四種Layout和與它們相對應的布局結構對象(Layout Data)。在*.custom包中,包含了對一些基本圖形構件的擴展,比如其中的CLabel,就是對標準Label構件的擴展,上面可以同時加入文字 和圖片,也可以加邊框。StyledText是Text構件的擴展,它提供了豐富的文本功能,比如對某段文字的背景色、前景色或字體的設置。在 *.custom包中也可找到一個新的StackLayout布局方式。

    SWT對用戶操作的響應,比如鼠標或鍵盤事件,也是采用了AWT和SWING中的Observer模式,在*.event包中可以找到事件監聽的 Listener接口和相應的事件對象,例如常用的鼠標事件監聽接口MouseListener,MouseMoveListener和 MouseTrackListener,及對應的事件對象MouseEvent。

    *.graphics包中可以找到針對圖片、光標、字體或繪圖的API。比如可通過Image類調用系統中不同類型的圖片文件。通過GC類實現對圖片、構件或顯示器的繪圖功能。

    對不同平臺,Eclipse還開發了一些富有針對性的API。例如,在Windows平臺,可以通過*.ole.win32包很容易的調用ole控件,這使Java程序內嵌IE瀏覽器或Word、Excel等程序成為可能!

    更復雜的程序

    下面讓我們展示一個比上面例子更加復雜一些的程序。這個程序擁有一個文本框和一個按鍵,當用戶點擊按鍵的時候,文本框顯示一句歡迎信息。

    為了文本框和按鍵有比較合理的大小和布局,這里采用了GradLayout布局方式。這種布局是SWT中最常用也是最強大的布局方式,幾乎所有的格式 都可能通過GradLayout去達到。下面的程序也涉及到了如何應用系統資源(Color),以及如何釋放系統資源。

    private void initShell(Shell shell) {
    //為Shell設置布局對象
    GridLayout gShellLay = new GridLayout();
    shell.setLayout(gShellLay);
    //構造一個Composite構件作為文本框和按鍵的容器
    Composite panel = new Composite(shell,SWT.NONE);
    //為Panel指定一個布局結構對象。
    這里讓Panel盡可能的占滿Shell,
    也就是全部應用程序窗口的空間。
    GridData gPanelData = new GridData(GridData.GRAB_HORIZONTAL| GridData.GRAB_VERTICAL|GridData.FILL_BOTH);
    panel.setLayoutData(gPanelData);
    //為Panel也設置一個布局對象。文本框和按鍵將按這個布局對象來顯示。
    GridLayout gPanelLay = new GridLayout();
    panel.setLayout(gPanelLay);
    //為Panel生成一個背景色
    final Color bkColor = new Color(Display.getCurrent(),200,0,200);
    panel.setBackground(bkColor);
    //生成文本框
    final Text text = new Text(panel,SWT.MULTI|SWT.WRAP);
    //為文本框指定一個布局結構對象,
    這里讓文本框盡可能的占滿Panel的空間。
    GridData gTextData = new GridData (GridData.GRAB_HORIZONTAL| GridData.GRAB_VERTICAL|GridData.FILL_BOTH);
    text.setLayoutData(gTextData);
    //生成按鍵
    Button butt = new Button(panel,SWT.PUSH);
    butt.setText("Push");
    //為按鍵指定鼠標事件
    butt.addMouseListener(new MouseAdapter(){
    public void mouseDown(MouseEvent e){
    //當用戶點擊按鍵的時候,顯示信息
    text.setText("Hello SWT");
    }
    });
    //當主窗口關閉時,會觸發DisposeListener。這里用來釋放Panel的背景色。
    shell.addDisposeListener(new DisposeListener(){
    public void widgetDisposed(DisposeEvent e) {
    bkColor.dispose();
    }
    });
    }

    把這段代碼中的方法initShell()加入到第一個打開空窗口的例子中,得到的是一段能成功運行的完整GUI應用程序。運行方法可參考第一個例子。  

    系統資源的管理

    在一個圖形化的操作系統中開發程序,都要調用系統中的資源,如圖片、字體、顏色等。通常這些資源都是有限的,程序員務必非常小心的使用這些資源:當不再使用它們時,就請盡快釋放,不然操作系統遲早會油盡燈枯,不得不重新啟動,更嚴重的會導致系統崩潰。
    SWT是用Java開發的,Java語言本身的一大優勢就是JVM的"垃圾回收機制",程序員通常不用理會變量的釋放,內存的回收等問題。那么對SWT而言,系統資源的操作是不是也是如此?答案是一個壞消息,一個好消息。

    壞消息是SWT并沒采用JVM的垃圾回收機制去處理操作系統的資源回收問題,一個關鍵的因素是因為JVM的垃圾回收機制是不可控的,也就是說程序員不 能知道,也不可能做到在某一時刻讓JVM回收資源!這對系統資源的處理是致命的,試想你的程序希望在一個循環語句中去查看數萬張圖片,常規的處理方式是每 次調入一張,查看,然后就立即釋放該圖片資源,而后在循環調入下一張圖片,這對操作系統而言,任何時刻程序占用的僅僅是一張圖片的資源。但如果這個過程完 全交給JVM去處理,也許會是在循環語句結束后,JVM才會去釋放圖片資源,其結果可能是你的程序還沒有運行結束,操作系統已經宕掉。

    但下面的好消息也許會讓這個壞消息變得無關緊要。對于SWT,只需了解兩條簡單的"黃金"法則就可以放心的使用系統資源!之所以稱為黃金法則,一是因 為少,只有兩條,二是因為它們出奇的簡單。第一條是"誰占用,誰釋放",第二條是"父構件被銷毀,子構件也同時被銷毀"。第一條原則是一個無任何例外的原 則,只要程序調用了系統資源類的構造函數,程序就應該關心在某一時刻要釋放這個系統資源。比如調用了

    Font font = new Font (display, "Courier", 10, SWT.NORMAL);

    那么就應該在不在需要這個Font的時候調用

    font.dispose();

    對于第二個原則,是指如果程序調用某一構件的dispose()方法,那么所有這個構件的子構件也會被自動調用dispose()方法而銷毀。通常這里指的子構件與父構件的關系是在調用構件的構造函數時形成的。比如,

    Shell shell = new Shell();
    Composite parent = new Composite(shell,SWT.NULL);
    Composite child = new Composite(parent,SWT.NULL);

    其中parent的父構件是shell,而shell則是程序的主窗口,所以沒有相應的父構件,同時parent又包括了child子構件。如果調用 shell.dispose()方法,應用第二條法則,那么parent和child構件的dispose()方法也會被SWT API自動調用,它們也隨之銷毀。

    線程問題

    在任何操作平臺的GUI系統中,對構件或一些圖形API的訪問操作都要被嚴格同步并串行化。例如,在一個圖形界面中的按鍵構件可被設成可用狀態 (enable)或禁用狀態(disable),正常的處理方式是,用戶對按鍵狀態設置操作都要被放入到GUI系統的事件處理隊列中(這意味著訪問操作被 串行化),然后依次處理(這意味著訪問操作被同步)。想象當按鍵可用狀態的設置函數還沒有執行結束的時候,程序就希望再設置該按鍵為禁用狀態,勢必會引起 沖突。實際上,這種操作在任何GUI系統都會觸發異常。

    Java語言本身就提供了多線程機制,這種機制對GUI編程來說是不利的,它不能保證圖形構件操作的同步與串行化。SWT采用了一種簡單而直接的方式 去適應本地GUI系統對線程的要求:在SWT中,通常存在一個被稱為"用戶線程"的唯一線程,只有在這個線程中才能調用對構件或某些圖形API的訪問操 作。如果在非用戶線程中程序直接調用這些訪問操作,那么SWTExcepiton異常會被拋出。但是SWT也在*.widget.Display類中提供 了兩個方法可以間接的在非用戶線程的進行圖形構件的訪問操作,這是通過的syncExec(Runnable)和asyncExec(Runnable) 這兩個方法去實現的。例如:

    //此時程序運行在一個非用戶線程中,并且希望在構件panel上加入一個按鍵。

    Display.getCurrent().asyncExec(new Runnable() {
    public void run() {
    Button butt = new Button(panel,SWT.PUSH);
    butt.setText("Push");
    }
    });

    方法syncExec()和asyncExec()的區別在于前者要在指定的線程執行結束后才返回,而后者則無論指定的線程是否執行都會立即返回到當前線程。

    SWT的擴展:JFace

    JFace與SWT的關系好比Microsoft的MFC與SDK的關系,JFace是基于SWT開發,其API比SWT更加易于使用,但功能卻沒SWT來的直接。比如下面的代碼應用JFace中的MessageDialog打開一個警告對話框:

    MessageDialog.openWarning(parent,"Warning","Warning message");

    如果只用SWT完成以上功能,語句不會少于30行!

    JFace原本是為更加方便的使用SWT而編寫的一組API,其主要目的是為了開發Eclipse IDE環境,而不是為了應用到其它的獨立應用程序。因此在Eclipse 2.1版本之前,很難將JFace API完整的從Eclipse的內核API中剝離出來,總是要多多少少導入一些非JFace以外的Eclipse核心代碼類或接口才能得到一個沒有任何編 譯錯誤的JFace開發包。但目前Eclipse組織似乎已經逐漸意識到了JFace在開發獨立應用程序起到的重要作用,在正在開發的2.1版本中, JFace也開始變成了和SWT一樣的完整獨立的開發包,只是這個開發包還在變動中(筆者寫本文時,應用的Eclipse2.1M3版本)。JFace開 發包的包前綴是以org.eclipse.jface開頭。JAR包和源代碼也和SWT一樣,也在${你的eclipse安裝路徑}\plugins路徑 下去找。

    對開發人員來說,在開發一個圖形構件的時候,比較好的方式是先到JFace包去找一找,看是不是有更簡潔的實現方法,如果沒有再用SWT包去自己實 現。比如JFace為對話框提供了很好的支持,除了各種類型的對話框(比如上面用的MessageDialog,或是帶有Title欄的對話框),如要實 現一個自定義的對話框也最好從JFace中的Dialog類繼承,而不是從SWT中的*.widget.Dialog繼承。

    應用JFace中的Preference包中的類很容易為自己的軟件做出一個很專業的配置對話框。對于Tree、Table等圖形構件,它們在顯示的 同時也要和數據關聯,例如Table中顯示的數據,在JFace中的View包中為此類構件提供了Model-View方式的編程方法,這種方法使顯示與 數據分開,更加利于開發與維護。JFace中提供最多的功能就是對文本內容的處理??梢栽趏rg.eclipse.jface.text.*包中找到數十 個與文本處理相關類。

    與應用程序更近一步

    Java程序通常是以class文件的方式發布的,運行class需要JRE或JDK的支持。這又是Java GUI程序的另一個致命的弱點,想象對一個面向廣大用戶的應用程序來說,無論你的程序功能有多簡單,或是你的代碼十分的精簡,你都不得不讓用戶去下載一個 7、8M的JRE,那是多么令人沮喪的一件事。而且對程序員來說,Class通常意味著源代碼的暴露,反編譯的工具讓那些居心叵測的人輕易得到你的源代 碼。雖然有很多對Class的加密方法,但那總是以犧牲性能為代價的。好在我們還有其它的方式可用:把Class編譯成exe文件!

    通過SWT開發包,簡單、跨平臺、可靠等這些Java語言本身所具有的優點正漸漸融合到圖形界面的應用程序開發中去。因此,我相信Java語言的另一扇成功之門正在逐漸打開。
    posted @ 2006-05-20 18:36 wqwqwqwqwq 閱讀(495) | 評論 (0)編輯 收藏
    僅列出標題
    共10頁: First 上一頁 2 3 4 5 6 7 8 9 10 下一頁 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567




    常用鏈接

    留言簿(10)

    隨筆分類(95)

    隨筆檔案(97)

    文章檔案(10)

    相冊

    J2ME技術網站

    java技術相關

    mess

    搜索

    •  

    最新評論

    閱讀排行榜

    校園夢網網絡電話,中國最優秀的網絡電話
    主站蜘蛛池模板: 亚洲人成网www| 亚洲经典千人经典日产| 99re热免费精品视频观看 | 午夜成年女人毛片免费观看| 亚洲AV无码专区在线厂| 亚洲不卡中文字幕无码| 成年女人男人免费视频播放| 成在人线av无码免费高潮水| 亚洲xxxxxx| 亚洲人成网亚洲欧洲无码久久| 国产一卡二卡3卡四卡免费| 一级做a爱过程免费视频高清| 亚洲精品在线电影| 亚洲无码视频在线| 久热中文字幕在线精品免费| 丰满妇女做a级毛片免费观看| 亚洲一级免费毛片| 亚洲国产美女精品久久久久∴| 成年美女黄网站色大免费视频| 99在线免费观看| 亚洲AV色无码乱码在线观看| 亚洲日本一区二区三区| 亚洲国模精品一区| 一二三四免费观看在线电影| 免费视频成人手机在线观看网址| 在线亚洲精品视频| 亚洲视频无码高清在线| 亚洲91av视频| 久久亚洲精品无码播放| 日本无吗免费一二区| 国产91免费在线观看| 久久精品乱子伦免费| 中国精品一级毛片免费播放| 亚洲精品理论电影在线观看| 亚洲美女视频免费| 久久久亚洲精品视频| 亚洲一级片内射网站在线观看| 热99re久久精品精品免费| 99在线精品视频观看免费| 久久午夜免费鲁丝片| 久久久受www免费人成|