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;


            //產(chǎn)生彩票主邏輯函數(shù)
             private static void Nicky(int[] guess){
                Random r = new Random();     //構(gòu)造偽隨機(jī)生成器
                //某些映射實(shí)現(xiàn)可明確保證其順序,如 TreeMap 類;某些映射實(shí)現(xiàn)則不保證順序,如 HashMap 類
                Map map = new TreeMap();   //Map 接口的實(shí)現(xiàn)
                int n = 0;
                int nt = 1;
                String[] temps=new String[7];
                
                while(true){
                    n = r.nextInt(33)+1; //產(chǎn)生1~33的隨機(jī)數(shù)
                    //if( map.get(new Integer(n))!=null){
                    //   nt = ((Integer)map.get(new Integer(n))).intValue();  
                    //}
                    //避免了產(chǎn)生的隨機(jī)數(shù)字重復(fù)
                    if(map.containsValue(n)){
                      continue;
                    }
                    map.put(new Integer(nt),new Integer(n));//將指定的值與此映射中的指定鍵相關(guān)聯(lián)
                    if(map.size()==7){
                       break;
                    }
                    nt++;
                }
                
                Iterator it = map.keySet().iterator(); //返回此映射中包含的鍵的 set 視圖
                for(int i=0;it.hasNext();i++){
                 Object o = it.next();
                  // 為了更符合現(xiàn)實(shí)中33選7,數(shù)字為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+"為產(chǎn)生的特別中獎中獎號碼");
                         }else  
                           System.out.println(""+transform+"為產(chǎn)生的第"+((Integer)o).intValue()+"個中獎號碼");
                  }else{
                  temps[i]=Integer.toString(temp);
                  match=match+" "+temps[i];
                  if(((Integer)o).intValue()==7){
                     System.out.println(""+transform+"為產(chǎn)生的特別中獎中獎號碼");
                  }else
                  System.out.println(""+temp+"為產(chǎn)生的第"+((Integer)o).intValue()+"個中獎號碼");
                 }
                }
                String creat=match.substring(3);
                System.out.println("所產(chǎn)生的中獎號碼串為:"+creat);
                //System.out.println("對產(chǎn)生的中獎號碼順序排序?yàn)?"+creats);
                Sort(temps);
                check(map,guess);
             }
             
             //實(shí)現(xiàn)排序,也可以調(diào)用方法,但是卻必須要解決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("對產(chǎn)生的中獎號碼順序排序?yàn)?");
                for(int i=0;i<temps.length;i++){
                    System.out.print(temps[i]+" ");
                }
                System.out.println("\n");
              }
             
             
            //輸出結(jié)果類別  
             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);
             }
             
             
            //主函數(shù)
             public static void main(String []args){
                  if(args.length==0||args.length>7){
                        usage();
                      }//帶入?yún)?shù)
                      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 閱讀(454) | 評論 (0)編輯 收藏
          呵呵 不知道寫的如何。但是總感覺,在UltraEdit下寫,還是很爽的,或許是因?yàn)閷W(xué)校辦公室的電腦內(nèi)存太小的緣故吧。
           1 /**
           2  * @the author:Nicky(EN) QuQiang(CH)
           3  * @the data :2006.8.27
           4  **/
           5 // 當(dāng)然本算法最好編制成兩到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     //定義返回數(shù)組類型的方法  此方法給出的public權(quán)限
          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:");  //對應(yīng)漢字為     按序排列為:
          23         for(int i=0;i<b.length;i++){
          24           System.out.println(b[i]);
          25         }                            //冒泡排序法排序  或直接使用JDK提供的sort()函數(shù)進(jìn)行排列
          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"); //對應(yīng)漢字為  "當(dāng)前共輸入" 個數(shù)符
          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         }             //考慮到用戶除輸入查找數(shù)符外,只輸入一個數(shù)符,即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;      //此時定義最大值為當(dāng)前中間值的前一個值  //第 次查找未成功,當(dāng)前值大于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;          //未找到,則在后半?yún)^(qū)間進(jìn)行查找  //小于
          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     //主函數(shù)的功能  傳入查找數(shù)組
          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         //輸出查詢結(jié)果
          88         switch(flag){
          89              //在本次折半查找中共經(jīng)過  次查找,未成功   成功
          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 閱讀(647) | 評論 (0)編輯 收藏
          前幾天參加了SUN在大連的暑期免費(fèi)培訓(xùn),主要是介紹了Netbeans集成開發(fā)環(huán)境和jdk1.5、1.6的一些新的特性。原來很少使用netbeans 來作程序,即使它是sun的產(chǎn)品。主要是因?yàn)?.1以前的版本過于garbage.但是參加完這次培訓(xùn)之后,對其很有信心。這次培訓(xùn)之后,我對sun的了解更加進(jìn)了一步。這次培訓(xùn)的老師是李濤老師和葉亮老師,這兩位老師我還是很佩服的。雖然sun的中國研究院,沒有微軟的那么大的名氣,但是我感覺這個團(tuán)體還是一個很令人敬佩和挑戰(zhàn)創(chuàng)新的團(tuán)體。我們無法想象沒有IDE的java編程,雖然在原來的文章中我更鼓勵初學(xué)者使用文本編輯工具。
              對于J2EE的框架理念我感覺這次沒有進(jìn)行深入的介紹,或與也是我感覺比較遺憾的一點(diǎn)了。
          下面給大家介紹一點(diǎn)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();
          }

          類型參數(shù)

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

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

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

          類型參數(shù)其實(shí)跟方法或構(gòu)造器中所用的通常參數(shù)相類似. 一個方法中可以聲明它用以處理的形式的值參數(shù), 相似地, 泛型聲明也有其形式的類型參數(shù); 當(dāng)方法被調(diào)用時, 實(shí)際參數(shù)會替換形式參數(shù), 然后執(zhí)行方法體, 同樣, 當(dāng)泛型聲明被調(diào)用時, 實(shí)際的類型參數(shù)會替換掉形式的類型參數(shù).

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




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

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

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

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

          這一點(diǎn)往往是最難以理解的, 因?yàn)樗屯ǔ5闹庇^相左. 在直觀的理解中, 我們實(shí)際上假定了集合是不會變動的, 但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);
          }}

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

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

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

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

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

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

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

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

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

          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 閱讀(570) | 評論 (0)編輯 收藏

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

          開發(fā)環(huán)境:Windows Server 2003 Standard Edition SP1, J2SDK 1.5.0_06, Eclipse 3.1.2
          源代碼如下:

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


          /**
           * 計算任意正整數(shù)的階乘
           * 
           *
           */
          public class Factorial {
           public static void main(String[] args) {
            BigInteger x = BigInteger.valueOf(1); //存儲結(jié)果
            int num = 1; //待計算的整數(shù)
            String s = null;
            boolean correct = false;
            do {
             try {
              s = JOptionPane.showInputDialog(null, "請輸入要計算的數(shù)(正整數(shù)):");
              if (s == null)
               break;
              else {
               num = Integer.parseInt(s);
               if (num < 0)
                throw new IllegalArgumentException();
               else correct = true;
              }  
             } catch (NumberFormatException e) {
              JOptionPane.showMessageDialog(null, "數(shù)據(jù)格式錯誤!");
              continue;
             } catch (IllegalArgumentException e) {
              JOptionPane.showMessageDialog(null,"請輸入一個正整數(shù)!");
              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,"階乘的結(jié)果");
             dialog.setVisible(true);
            }
            System.exit(0);
           }
          }

           

          運(yùn)行結(jié)果如下:

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

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

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

              假使我們?yōu)镠ello類增加一個main方法,雖然它也是static的,但是靜態(tài)初始化塊會在main之前被執(zhí)行。

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

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


              二、如果您想了解更多的細(xì)節(jié),請查看如下的資料:

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

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

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

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

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

          /**
           * 程序運(yùn)行當(dāng)年的日歷,程序運(yùn)行當(dāng)日以*號表示
           */

          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);                  //設(shè)置為當(dāng)年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);    //獲得當(dāng)月1號,在一周中是星期幾
             for(int i = Calendar.SUNDAY; i < weekday; i++)//控制當(dāng)月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)) //如果是當(dāng)日,則輸出一個*號
               System.out.print("* ");
              else
               System.out.print("  ");
              if (weekday == Calendar.SATURDAY)         //到達(dá)周六,則換行
               System.out.println();
              d.add(Calendar.DAY_OF_YEAR,1);            //日期累加
             } while (d.get(Calendar.MONTH) == month);     //如果還是當(dāng)月,繼續(xù)循環(huán)
             System.out.println("\n");
            } while (d.get(Calendar.YEAR) == year);           //如果還是當(dāng)年,繼續(xù)循環(huán)
           }
          }
          posted @ 2006-07-22 17:17 wqwqwqwqwq 閱讀(367) | 評論 (0)編輯 收藏
          動機(jī):
          充分利用java陣營眾多的類庫

          工具:

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

          winrar――提取jar,打包jar

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

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

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

          一是指性能上的穩(wěn)定,其中的關(guān)鍵是源于SWT的設(shè)計理念。SWT最大化了操作系統(tǒng)的圖形構(gòu)件API,就是說只要操作系統(tǒng)提供了相應(yīng)圖形的構(gòu)件,那么 SWT只是簡單應(yīng)用JNI技術(shù)調(diào)用它們,只有那些操作系統(tǒng)中不提供的構(gòu)件,SWT才自己去做一個模擬的實(shí)現(xiàn)。可以看出SWT的性能上的穩(wěn)定大多時候取決于 相應(yīng)操作系統(tǒng)圖形構(gòu)件的穩(wěn)定性。

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

          第一個SWT程序

          下面讓我們開始一個SWT程序。(注意:以下的例子和說明主要針對Windows平臺,其它的操作系統(tǒng)應(yīng)該大同小異)。首先要在Eclipse安裝文 件中找到SWT包,Eclipse組織并不提供單獨(dú)的SWT包下載,必須下載完整的Eclipse開發(fā)環(huán)境才能得到SWT包。SWT是作為Eclipse 開發(fā)環(huán)境的一個插件形式存在,可以在${你的eclipse安裝路徑}\plugins路徑下的眾多子目錄下去搜索SWT.JAR文件,在找到的JAR文 件中包含了SWT全部的Java類文件。因?yàn)镾WT應(yīng)用了JNI技術(shù),因此同時也要找到相對應(yīng)的JNI本地化庫文件,由于版本和操作平臺的不同,本地化庫 文件的名稱會有些差別,比如SWT-WIN32-2116.DLL是Window平臺下Eclipse Build 2116的動態(tài)庫,而在Unix平臺相應(yīng)版本的庫文件的擴(kuò)展名應(yīng)該是.so,等等。注意的是,Eclipse是一個開放源代碼的項目,因此你也可以在這些 目錄中找到SWT的源代碼,相信這會對開發(fā)很有幫助。下面是一段打開空窗口的代碼(只有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();
          // 開始事件處理循環(huán),直到用戶關(guān)閉窗口
          while (!shell.isDisposed()) {
          if (!display.readAndDispatch())
          display.sleep();
          }
          display.dispose();
          }
          }

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

          剖析SWT API

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

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

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

          *.graphics包中可以找到針對圖片、光標(biāo)、字體或繪圖的API。比如可通過Image類調(diào)用系統(tǒng)中不同類型的圖片文件。通過GC類實(shí)現(xiàn)對圖片、構(gòu)件或顯示器的繪圖功能。

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

          更復(fù)雜的程序

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

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

          private void initShell(Shell shell) {
          //為Shell設(shè)置布局對象
          GridLayout gShellLay = new GridLayout();
          shell.setLayout(gShellLay);
          //構(gòu)造一個Composite構(gòu)件作為文本框和按鍵的容器
          Composite panel = new Composite(shell,SWT.NONE);
          //為Panel指定一個布局結(jié)構(gòu)對象。
          這里讓Panel盡可能的占滿Shell,
          也就是全部應(yīng)用程序窗口的空間。
          GridData gPanelData = new GridData(GridData.GRAB_HORIZONTAL| GridData.GRAB_VERTICAL|GridData.FILL_BOTH);
          panel.setLayoutData(gPanelData);
          //為Panel也設(shè)置一個布局對象。文本框和按鍵將按這個布局對象來顯示。
          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);
          //為文本框指定一個布局結(jié)構(gòu)對象,
          這里讓文本框盡可能的占滿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");
          //為按鍵指定鼠標(biāo)事件
          butt.addMouseListener(new MouseAdapter(){
          public void mouseDown(MouseEvent e){
          //當(dāng)用戶點(diǎn)擊按鍵的時候,顯示信息
          text.setText("Hello SWT");
          }
          });
          //當(dāng)主窗口關(guān)閉時,會觸發(fā)DisposeListener。這里用來釋放Panel的背景色。
          shell.addDisposeListener(new DisposeListener(){
          public void widgetDisposed(DisposeEvent e) {
          bkColor.dispose();
          }
          });
          }

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

          系統(tǒng)資源的管理

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

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

          但下面的好消息也許會讓這個壞消息變得無關(guān)緊要。對于SWT,只需了解兩條簡單的"黃金"法則就可以放心的使用系統(tǒng)資源!之所以稱為黃金法則,一是因 為少,只有兩條,二是因?yàn)樗鼈兂銎娴暮唵巍5谝粭l是"誰占用,誰釋放",第二條是"父構(gòu)件被銷毀,子構(gòu)件也同時被銷毀"。第一條原則是一個無任何例外的原 則,只要程序調(diào)用了系統(tǒng)資源類的構(gòu)造函數(shù),程序就應(yīng)該關(guān)心在某一時刻要釋放這個系統(tǒng)資源。比如調(diào)用了

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

          那么就應(yīng)該在不在需要這個Font的時候調(diào)用

          font.dispose();

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

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

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

          線程問題

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

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

          //此時程序運(yùn)行在一個非用戶線程中,并且希望在構(gòu)件panel上加入一個按鍵。

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

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

          SWT的擴(kuò)展:JFace

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

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

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

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

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

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

          與應(yīng)用程序更近一步

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

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

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

          一是指性能上的穩(wěn)定,其中的關(guān)鍵是源于SWT的設(shè)計理念。SWT最大化了操作系統(tǒng)的圖形構(gòu)件API,就是說只要操作系統(tǒng)提供了相應(yīng)圖形的構(gòu)件,那么 SWT只是簡單應(yīng)用JNI技術(shù)調(diào)用它們,只有那些操作系統(tǒng)中不提供的構(gòu)件,SWT才自己去做一個模擬的實(shí)現(xiàn)。可以看出SWT的性能上的穩(wěn)定大多時候取決于 相應(yīng)操作系統(tǒng)圖形構(gòu)件的穩(wěn)定性。

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

          第一個SWT程序

          下面讓我們開始一個SWT程序。(注意:以下的例子和說明主要針對Windows平臺,其它的操作系統(tǒng)應(yīng)該大同小異)。首先要在Eclipse安裝文 件中找到SWT包,Eclipse組織并不提供單獨(dú)的SWT包下載,必須下載完整的Eclipse開發(fā)環(huán)境才能得到SWT包。SWT是作為Eclipse 開發(fā)環(huán)境的一個插件形式存在,可以在${你的eclipse安裝路徑}\plugins路徑下的眾多子目錄下去搜索SWT.JAR文件,在找到的JAR文 件中包含了SWT全部的Java類文件。因?yàn)镾WT應(yīng)用了JNI技術(shù),因此同時也要找到相對應(yīng)的JNI本地化庫文件,由于版本和操作平臺的不同,本地化庫 文件的名稱會有些差別,比如SWT-WIN32-2116.DLL是Window平臺下Eclipse Build 2116的動態(tài)庫,而在Unix平臺相應(yīng)版本的庫文件的擴(kuò)展名應(yīng)該是.so,等等。注意的是,Eclipse是一個開放源代碼的項目,因此你也可以在這些 目錄中找到SWT的源代碼,相信這會對開發(fā)很有幫助。下面是一段打開空窗口的代碼(只有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();
          // 開始事件處理循環(huán),直到用戶關(guān)閉窗口
          while (!shell.isDisposed()) {
          if (!display.readAndDispatch())
          display.sleep();
          }
          display.dispose();
          }
          }

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

          剖析SWT API

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

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

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

          *.graphics包中可以找到針對圖片、光標(biāo)、字體或繪圖的API。比如可通過Image類調(diào)用系統(tǒng)中不同類型的圖片文件。通過GC類實(shí)現(xiàn)對圖片、構(gòu)件或顯示器的繪圖功能。

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

          更復(fù)雜的程序

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

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

          private void initShell(Shell shell) {
          //為Shell設(shè)置布局對象
          GridLayout gShellLay = new GridLayout();
          shell.setLayout(gShellLay);
          //構(gòu)造一個Composite構(gòu)件作為文本框和按鍵的容器
          Composite panel = new Composite(shell,SWT.NONE);
          //為Panel指定一個布局結(jié)構(gòu)對象。
          這里讓Panel盡可能的占滿Shell,
          也就是全部應(yīng)用程序窗口的空間。
          GridData gPanelData = new GridData(GridData.GRAB_HORIZONTAL| GridData.GRAB_VERTICAL|GridData.FILL_BOTH);
          panel.setLayoutData(gPanelData);
          //為Panel也設(shè)置一個布局對象。文本框和按鍵將按這個布局對象來顯示。
          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);
          //為文本框指定一個布局結(jié)構(gòu)對象,
          這里讓文本框盡可能的占滿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");
          //為按鍵指定鼠標(biāo)事件
          butt.addMouseListener(new MouseAdapter(){
          public void mouseDown(MouseEvent e){
          //當(dāng)用戶點(diǎn)擊按鍵的時候,顯示信息
          text.setText("Hello SWT");
          }
          });
          //當(dāng)主窗口關(guān)閉時,會觸發(fā)DisposeListener。這里用來釋放Panel的背景色。
          shell.addDisposeListener(new DisposeListener(){
          public void widgetDisposed(DisposeEvent e) {
          bkColor.dispose();
          }
          });
          }

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

          系統(tǒng)資源的管理

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

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

          但下面的好消息也許會讓這個壞消息變得無關(guān)緊要。對于SWT,只需了解兩條簡單的"黃金"法則就可以放心的使用系統(tǒng)資源!之所以稱為黃金法則,一是因 為少,只有兩條,二是因?yàn)樗鼈兂銎娴暮唵巍5谝粭l是"誰占用,誰釋放",第二條是"父構(gòu)件被銷毀,子構(gòu)件也同時被銷毀"。第一條原則是一個無任何例外的原 則,只要程序調(diào)用了系統(tǒng)資源類的構(gòu)造函數(shù),程序就應(yīng)該關(guān)心在某一時刻要釋放這個系統(tǒng)資源。比如調(diào)用了

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

          那么就應(yīng)該在不在需要這個Font的時候調(diào)用

          font.dispose();

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

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

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

          線程問題

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

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

          //此時程序運(yùn)行在一個非用戶線程中,并且希望在構(gòu)件panel上加入一個按鍵。

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

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

          SWT的擴(kuò)展:JFace

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

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

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

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

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

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

          與應(yīng)用程序更近一步

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

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




          常用鏈接

          留言簿(10)

          隨筆分類(95)

          隨筆檔案(97)

          文章檔案(10)

          相冊

          J2ME技術(shù)網(wǎng)站

          java技術(shù)相關(guān)

          mess

          搜索

          •  

          最新評論

          閱讀排行榜

          校園夢網(wǎng)網(wǎng)絡(luò)電話,中國最優(yōu)秀的網(wǎng)絡(luò)電話
          主站蜘蛛池模板: 文化| 凤台县| 兴文县| 定兴县| 沅江市| 台南市| 鄂托克前旗| 浪卡子县| 扎赉特旗| 中阳县| 常州市| 虹口区| 河北省| 财经| 内江市| 大庆市| 兰溪市| 斗六市| 延川县| 肇东市| 林西县| 远安县| 恭城| 福州市| 武定县| 西乌珠穆沁旗| 虞城县| 张掖市| 博野县| 建德市| 乐昌市| 松桃| 会宁县| 通河县| 六安市| 光泽县| 连城县| 沁源县| 乌苏市| 安多县| 广安市|