我的JAVA窩! - BlogJava

          2008年9月15日

          Got Source Code of Kettle

            Using Kettle for more than one year in my project, but still have no time to read the source code of Kettle untill couple of days before (busy or actually lazy?). Yeah, I am a lazy dog...
            Since the source code is not available directly from the Pentato website, I had no choice but to go thru some posts on the Pentaho forum one by one. It didn't take me much effor before I found the relevant post, thx god:) The source code of Kettle now is maintained in SVN of JavaForge, and anybody "can get the latest(subversion trunk) code changes with on this URL: http://svn.javaforge.com/svn/Kettle/trunk", the username is "anonymous" and password is "anon".
            Besides, I had to download a SVN tool. I am using TortoiseSVN in my company, and the ux satisfied me, so I chose it again.
            It taked about 30 minutes to check out all the source code (still very fast I think, my bandwidth is 2M).
            When it done, I imported it as a general project into eclipse, and one thing surprised me a little bit was that, I didn't have to compile the source code or import some jars even than execute a Ant target manually as I built the source code of Spring before. Hah, Kettle is developed by using eclipse?! (you can find some eclipse project files in the trunk).
            Anyway, the work was going on smoothly, no more than 40 minutes. Now I can debug the Kettle, and from my experience, in some scenarios Kettle doesn't work in good performace than I expect, and even sometimes it runs into some bugs when I do the multitudinous insert or update operations. Here I get the opportunity to look into the code and figure out the problem.

            Keep moving forward...

          posted @ 2008-09-15 18:24 J2S 閱讀(1598) | 評論 (3)編輯 收藏

          2007年3月19日

          集合框架類筆記的補充

          java .util.*定義了一系列的接口和類,告訴我們用什么類NEW出一個對象,可以進行超越數(shù)組的操作。
          (注:JAVA1.5對JAVA1.4的最大改進就是增加了對范型的支持)

          Set接口是數(shù)學(xué)中集合的概念:其元素?zé)o序,且不可重復(fù)。(正好與List對應(yīng))

          !!注意數(shù)組和集合的區(qū)別:數(shù)組中只能存簡單數(shù)據(jù)類型。Collection接口和Map接口只能存對象。

          只有List可用get和size。而Set則不可用(因其無序)。

          集合中每一個元素都有對象,如有字符串要經(jīng)過強制類型轉(zhuǎn)換。

          Collections是工具類,所有方法均為有用方法,且方法為static。


          Collections.Sort()分為兩部分,一部分為排序規(guī)則;一部分為排序算法。
          規(guī)則用來判斷對象;算法是考慮如何排序。
          對于自定義對象,Sort不知道規(guī)則,所以無法比較。這種情況下一定要定義排序規(guī)則。方式有兩種:
          java.lang下面有一個接口:Comparable(可比較的)
          可以讓自定義對象實現(xiàn)一個接口,這個接口只有一個方法comparableTo(Object o)
          其規(guī)則是當(dāng)前對象與o對象進行比較,其返回一個int值,系統(tǒng)根據(jù)此值來進行排序。
          如 當(dāng)前對象>o對象,則返回值>0;(可將返回值定義為1)
          如 當(dāng)前對象=o對象,則返回值=0;
          如 當(dāng)前對象<o對象,則返回值〈0。(可將返回值定義為-1)
          看TestArraylist的java代碼。
          我們通過返回值1和-1位置的調(diào)換來實現(xiàn)升序和降序排列的轉(zhuǎn)換。

          java.util下有一個Comparator(比較器)
          它擁有compare(),用來比較兩個方法。
          要生成比較器,則用Sort中Sort(List,List(Compate))
          第二種方法更靈活,且在運行的時候不用編譯。

          注意:要想實現(xiàn)comparTo()就必須在主方法中寫上implement comparable.


          集合的最大缺點是無法進行類型判定(這個缺點在JAVA1.5中已經(jīng)解決),這樣就可能出現(xiàn)因為類型不同而出現(xiàn)類型錯誤。
          解決的方法是添加類型的判斷。

          而在LinkedList的底層是一種雙向循環(huán)鏈表。在此鏈表上每一個數(shù)據(jù)節(jié)點都由三部分組成:前指針(指向前面的節(jié)點的位置),數(shù)據(jù),后指針(指向后面的節(jié)點的位置)。最后一個節(jié)點的后指針指向第一個節(jié)點的前指針,形成一個循環(huán)。

          LinkedList經(jīng)常用在增刪操作較多而查詢操作很少的情況下:隊列和堆棧。
          隊列:先進先出的數(shù)據(jù)結(jié)構(gòu)。
          堆棧:后進先出的數(shù)據(jù)結(jié)構(gòu)。
          注意:使用堆棧的時候一定不能提供方法讓不是最后一個元素的元素獲得出棧的機會。
          LinkedList提供以下方法:(ArrayList無此類方法)
          addFirst();
          removeFirst();
          addLast();
          removeLast();


          Push用addFirst();pop用removeFirst(),實現(xiàn)后進先出。
          用isEmpty()--其父類的方法,來判斷棧是否為空。

          在隊列中,put為入隊列操作,get為出隊列操作。
          Put用addFirst(),get用removeLast()實現(xiàn)隊列。

          List接口的實現(xiàn)類(Vector)(與ArrayList相似,區(qū)別是Vector是重量級的組件,使用使消耗的資源比較多。)
          結(jié)論:在考慮并發(fā)的情況下用Vector(保證線程的安全)。
          在不考慮并發(fā)的情況下用ArrayList(不能保證線程的安全)。

          面試經(jīng)驗(知識點):
          java.util.stack(stack即為堆棧)的父類為Vector。可是stack的父類是最不應(yīng)該為Vector的。因為Vector的底層是數(shù)組,且Vector有g(shù)et方法(意味著它可能訪問到并不屬于最后一個位置元素的其他元素,很不安全)。
          對于堆棧和隊列只能用push類和get類。
          Stack類以后不要輕易使用。
          !!!實現(xiàn)堆棧一定要用LinkedList。


          (在JAVA1.5中,collection有queue來實現(xiàn)隊列。)








          posted @ 2007-03-19 22:04 J2S 閱讀(565) | 評論 (1)編輯 收藏

          關(guān)于集合框架類的學(xué)習(xí)筆記

          集合類

          集合類的對象是用來管理其他若干對象的,它類似于C++標(biāo)準(zhǔn)模板庫中的容器,不過在JAVA的集合類的對象中可以用來存放多種類型的對象。

          接口和類共同構(gòu)成了一個集合框架,集合的概念,一個對象可以裝載多個對象,這個對象就是集合對象。

          集合框架

          1,接口

          Collection 用來管理多個對象,集合中的每個元素都是對象。

          Map,Map中沒有對象,而是鍵值對,由Key,value組成的鍵值對,Key是不可重復(fù)的。value是可以相同的,一個Key和一個value一一對應(yīng)。

          集合中用到的類,接口在java.util包中,在使用時注意將其引入import。

          Collection 接口(以下介紹其子接口)

          1)List 一個List的實現(xiàn)類的對象在管理多個對象時會按順序組織對象(即按照將對象放入的順序存儲),List實現(xiàn)類的對象是由順序的。(注意,順序和排序的區(qū)別)

          2)Set 一個Set的實現(xiàn)類表示一個數(shù)學(xué)概念上的集合,Set的實現(xiàn)類的對象中的元素是無順序的,也就是不會按照輸入順序來存放,Set的實現(xiàn)類對象中的元素是不重復(fù)的。

          3)SortedSet,他是Set的子接口,他的實現(xiàn)類會對集合中的元素進行排序。但是要指定排序規(guī)則,他會按排序規(guī)則進行排序。

          Map 接口(以下介紹其子接口)

          SortedMap,這個接口的實現(xiàn)類同樣可以實現(xiàn),不過是對鍵值對中的Key進行排序,這個接口的實現(xiàn)類也是要指定排序規(guī)
          則的。

          JDK1.4中的集合是不安全的對象,JDK5.0中解決了這個問題

          List接口的實現(xiàn)類

          1> ArrayList是接近于功能的集合類,ArryList的實質(zhì)就是一個會自動增長的數(shù)組,ArrayList是用封裝的數(shù)組來實現(xiàn)的List接口的。

          Collection的實現(xiàn)類對象的遍歷方式是用迭代來實現(xiàn)的。
          在使用迭代器時先要活得一個迭代器的對象,Iterator(迭代器接口)這是一個接口,迭代器是在集合類中實現(xiàn)的,也
          就是說,他是一個內(nèi)部類(匿名內(nèi)部類)實現(xiàn)的。
          Iterator接口中定義的常用方法方法hasNext(),next()。
          hasNext(),這個方法會使用一個游標(biāo),并通過判斷游標(biāo)指向的位置是否存放有對象。
          next()方法也是Iterator接口中定義好的方法,這個方法會使游標(biāo)指向下一個元素的位置,游標(biāo)會跳過第一個元素,并
          返回其中的內(nèi)容。

          Collections 這是一個工具類,也是java.util包中的,這個類中的sort(list接口的實現(xiàn)類的對象)方法,其參數(shù)是一個集合類的對象,這個方法使用來對集合類的對象進行排序的。以后,我將以集合這個名字來稱呼集合類的對象。,對于
          字符串對象內(nèi)容的集合來說會按字典順序排序(升序),對于數(shù)字內(nèi)容的集合排序也會按照升序排序

          排序可一份為兩部分內(nèi)容,一個是排序的規(guī)則,也就是按照什么來進行排序,并且排成什么樣的順序。
          第二個就是排序的算法,他決定了排序的效率。

          在對自定義的集合內(nèi)容類型排序時,需要先定義那個類型的排序規(guī)則。

          Comparable接口,這個接口中只定義了一個compareTo(Object o),方法的返回至類型是整型,如果當(dāng)前對象大于參數(shù)對象就返回正數(shù),當(dāng)前對象等于參數(shù)對象是就返回0,當(dāng)前對象小于參數(shù)對象時就返回負(fù)值,這樣寫就是升序排列,反之則是進行降序排列,在實現(xiàn)這個接口中的方法時,返回值定義方式,只有這兩種。

          根據(jù)指定類型的排序規(guī)則實現(xiàn)了Comparable接口,那么就可以對存有這個類型的集合進行整體排序。Comparable接口,
          也叫做可比較接口。這個接口在java.lang包下。只要實現(xiàn)了這個接口,就是可排序的

          接下來介紹另外一種對自定義類型對象的集合整體排序的方法,也就是實現(xiàn)比較器接口(Comparator),這個接口中定義了一個compare(Object o1,Object o2)方法來比較兩個對象,這個方法的返回值定義和上面介紹的那個方法是一樣。

          注意:在API,幫助文檔中以上兩個方法的參數(shù)類型是T,這代表的模板類型,也就是集合中存放的內(nèi)容的類型,在JDK1.4中其參數(shù)就是Object類型,模板類型的詳細內(nèi)容會在最后的JDK5.0新特性中講到。

          Comparator接口可以在匿名內(nèi)部類中實現(xiàn),Collections 中的sort(集合了的對象,比較器)方法,可以對自定義類型內(nèi)容的集合進行整體排序。

          2>LinkedList,它是List接口的實現(xiàn)類,其底層是用雙向循環(huán)鏈表來實現(xiàn)的

          注意:ArrayList的查詢效率比較高,增刪動作的效率比較差,適用于查詢比較頻繁,增刪動作較少的元素管理的集合。
          ? ? ?LinkedList的查詢效率低,但是增刪效率很高。適用于增刪動作的比較頻繁,查詢次數(shù)較少的元素管理集合。

          ArrayList,LinkedList都是線程不安全的
          實現(xiàn)堆棧 1,數(shù)組(ArrayList,增刪效率比較低,不適合)
          ? ? ? ? 2,LinkedList實現(xiàn)堆棧的好方法
          ? ? ? ? 3,java.util.Stack類,Stack是Vector的子類,Vector類是一個線程安全的(是一個重量級的類),并繼承
          了Vector的方法,Verctor類和ArrayList的功能近乎相同。(不推薦使用Stack類來實現(xiàn)堆棧)。

          Set接口的實現(xiàn)類

          HashSet

          Set的實現(xiàn)類的集合對象中不能夠有重復(fù)元素,HashSet也一樣他是使用了一種標(biāo)識來確定元素的不重復(fù),HashSet用一種算法來保證HashSet中的元素是不重復(fù)的,HashSet的底層實現(xiàn)還是數(shù)組

          Object類中的hashCode()的方法是所有子類都會繼承這個方法,這個方法會用Hash算法算出一個Hash(哈希)碼值返回,HashSet會用Hash碼值去和數(shù)組長度取模,模(這個模就是對象要存放在數(shù)組中的位置)相同時才會判斷數(shù)組中的元素和要加入的對象的內(nèi)容是否相同,如果不同才會添加進去。

          Hash算法是一種散列算法。

          注意:所以要存入HashSet的集合對象中的自定義類必須覆蓋hashCode(),equals()兩個方法,才能保證集合中元素容不重復(fù)。在覆蓋和hashCode()方法時,要使相同對象的hashCode()方法返回相同值,覆蓋equals()方法再判斷其內(nèi)容。為了保證效率,所以在覆蓋hashCode()方法時,也要盡量使不同對象盡量返回不同的Hash碼值。

          如果數(shù)組中的元素和要加入的對象的hashCode()返回了相同的Hash值(相同對象),才會用equals()方法來判斷兩個對象的內(nèi)容是否相同。

          SortedSet接口是Set的子接口。
          TreeSet是SortedSet接口的實現(xiàn)類,他可以對集合中的元素進行排序。
          要存放在TreeSet中自定義類的對象,這個類要么是已經(jīng)實現(xiàn)了Comparable接口,要么是能給出Comparator比較器,TreeSet可以自動過濾掉重復(fù)元素所以不用重載hashCode()方法,TreeSet會根據(jù)比較規(guī)則判斷元素內(nèi)容是否相同,TreeSet會在元素存入世就進行了排序。(在TreeSet給出排序規(guī)則時,一定要注意對象內(nèi)容相等的條件,一定要注意在主觀的認(rèn)為兩個對象內(nèi)容相同時,才可以使用比較少的條件來進行判斷)

          要排序時才使用TreeSet類(存儲效率比較低),HashSet的存儲效率比較高,在需要為HashSet的對象排序時,就可以把HashSet中的元素放入TreeSet。

          posted @ 2007-03-19 21:55 J2S 閱讀(1189) | 評論 (0)編輯 收藏

          2007年2月21日

          如何最快成為有錢人

          通向財富的道路有千萬條,但條條道路都驚人地相似。而且令人詫異的是,拼命積累財富的男人也驚人地相似,他們在心理特征上就像是同一個模子壓出來的一樣。

          ??? 百萬富翁有諸多特征,絕大多數(shù)白手起家的百萬富翁都是出身貧窮的人,積累金錢對于那些一貧如洗的人有著不可抗拒的力量。

          ??? 這些男人是很有冒險精神的,他們敢于冒那些腳踏實地、像苦工似地掙錢的男人所不敢涉足的風(fēng)險。他們是精明強干的,他們很有遠見卓識;他們的天才在于能知道如何利用別人的主意來賺錢。這是賺錢的真正秘訣——利用別人創(chuàng)造性的思想,并且把它們運用到實際中去。

          ??? 這樣的男人很容易和別人打成一片。他們很有洞察力,他們會觀察別人,知道如何通過與別人打交道來獲得他們所需要的東西,也知道別人對他們的反應(yīng)如何。追求財富的人內(nèi)心深處有著強烈的孤獨感,但他們并不因此而去追求政治上的名望和成就。賺錢是他們絕對全神貫注的追求。這給他們勝于一切的最大滿足和快樂。

          ??? 1、讓金錢成為你的情人。

          ??? 別在性愛上浪費時間和精力,你會發(fā)現(xiàn),從長遠來看,賺錢比性愛更讓人興奮,這可不是空頭支票。尋求需求,滿足需求。追求財富者的最大天分是瞄準(zhǔn)時機,預(yù)測所需。大眾牌小汽車,美國快餐食品都是滿足人們需要的例子。

          ??? 2、謹(jǐn)防從眾心理。

          ??? 群眾心理弊病多,即使它是正確的,追隨它一般也沒有什么利潤。在一般情況下,摘取經(jīng)濟精華的都是帶頭人而不是追隨者。

          ??? 3、當(dāng)雇主而不是雇員。

          ??? 那些滿足于雇主付給他們高薪的男人并不是真正追求財富的人,他們的目標(biāo)僅僅是成就感或權(quán)力欲。你最好去當(dāng)老板,即使雇員只有你一個,賺的錢也會比任何一個公司付給你的多。

          ??? 4、發(fā)展你的支配技巧。

          ??? 大多數(shù)人認(rèn)為,支配別人,讓他們?nèi)プ瞿阆胱屗麄兏傻氖虑榉浅毫印H欢瑢嶋H情況是,我們時時都在自己沒有意識到的情況下支配著別人。

          ??? 5、追求財富的人常常是直覺地支配著別人,而且是個行家里手。
          ?

          posted @ 2007-02-21 15:40 J2S 閱讀(235) | 評論 (0)編輯 收藏

          2007年1月18日

          終于解脫了...

          ????????下午答辯,還算順利,雖然花了半天時間,沒任何技術(shù)含量,但是終于解脫了...

          ?????????五天來平均每天也就睡了不到兩小時,現(xiàn)在真有點頂不住了(意識都模糊了),但是為了把生物鐘調(diào)整過來,還是撐一會吧。突然閑下來卻不知道做點什么,20號有個面試,等會沒事把Struts那本書再看看。

          ?????????接下來都不知道寫些什么東西,就把實踐中的一個弄明白的一個小知識記一下:
          在JDBC中,對于游標(biāo)對象ResultSet的getString()方法也是用游標(biāo)的模式來讀取數(shù)據(jù)的(不知道這樣描敘對不對),即,你要取字段1,字段2,就必須先調(diào)用rs.getString(1),再調(diào)用rs.getString(2),不能反過來,否則不能正確讀取。原因還不知道,有空了研究一下。

          posted @ 2007-01-18 19:56 J2S 閱讀(386) | 評論 (3)編輯 收藏

          2007年1月15日

          期末實踐中......

          今天成績都出來了,結(jié)果還是比較理想的,以后會相對輕松些。

          更新日志都是半個月前的事了,當(dāng)時還說以后每天都更新,真是慚愧

          這幾天都是忙考試,弄得心力憔悴,今天晚上終于閑下來,繼續(xù)寫實踐的程序。

          剛剛解決了前幾個小時的困惑,現(xiàn)在對JAVA的內(nèi)部類機制又有了更新的認(rèn)識(興奮中......),廢話少說,來看代碼:

          package tanzhang;

          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.ResultSet;
          import java.sql.Statement;

          import org.eclipse.swt.SWT;
          import org.eclipse.swt.events.SelectionAdapter;
          import org.eclipse.swt.events.SelectionEvent;
          import org.eclipse.swt.widgets.Button;
          import org.eclipse.swt.widgets.Combo;
          import org.eclipse.swt.widgets.Composite;
          import org.eclipse.swt.widgets.Display;
          import org.eclipse.swt.widgets.Label;
          import org.eclipse.swt.widgets.Shell;
          import org.eclipse.swt.widgets.TabFolder;
          import org.eclipse.swt.widgets.Table;
          import org.eclipse.swt.widgets.TableColumn;
          import org.eclipse.swt.widgets.TableItem;
          import org.eclipse.swt.widgets.Text;
          import com.swtdesigner.SWTResourceManager;
          import org.eclipse.swt.widgets.TabItem;
          public class tanzhang {

          ?/**
          ? * Launch the application
          ? * @param args
          ? */
          ?private static Table table;
          ?private static TableItem newItemTableItem;

          ?
          ?public static void main(String[] args) {
          ??final Display display = Display.getDefault();
          ??final Shell shell = new Shell();
          ??shell.setImage(SWTResourceManager.getImage(tanzhang.class, "/org/eclipse/ui/internal/forms/widgets/progress.gif"));
          ??shell.setSize(774, 514);
          ??shell.setText("宣城供電局消弧線圈臺帳");
          ............
          ............
          ............
          ??final Combo combo_1 = new Combo(composite, SWT.READ_ONLY);
          ??combo_1.addSelectionListener(new SelectionAdapter() {
          ???public void widgetSelected(SelectionEvent arg0) {
          ????String str=combo_1.getText();
          ????try{?
          ?????String dbUrl = "jdbc:odbc:test";
          ?????Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
          ?????Connection conn = DriverManager.getConnection(dbUrl, "", "");
          ?????Statement stmt=conn.createStatement();
          ?????String sql="SELECT * from test where 單元名稱="+str;
          ?????ResultSet rs=stmt.executeQuery(sql);
          ?????
          ?????if(rs.next()){
          ?????for(int i=0;i<=4;i++){?????????
          ???????newItemTableItem.setText(i,rs.getString(i+1));??
          ???????}
          ?????
          ?????rs.close();
          ?????stmt.close();
          ?????conn.close();
          ?????}
          ????}catch(Exception e){}
          ????
          ???}
          ??});
          ............
          ............
          ............

          ??table = new Table(composite_1, SWT.VIRTUAL | SWT.FULL_SELECTION | SWT.BORDER | SWT.HIDE_SELECTION);

          ??table.setLinesVisible(true);
          ??table.setHeaderVisible(true);
          ??table.setBounds(0, 0, 678, 80);
          ............
          ............
          ............

          ???剛開始是用final修飾table和newItemTableItem,但是“newItemTableItem.setText(i,rs.getString(i+1));”這行(代碼中蘭色那句)會報錯,編譯器提示“無法解析newItemTableItem”。我的第一反應(yīng)是監(jiān)聽器的位置放得不對。翻了一下書,說SWT/JFace事件代碼中要訪問類中變量有三種方法:(1)加final;(2)將變量變?yōu)轭惖膶嵗兞浚唬?)將事件代碼寫成命名內(nèi)部類,然后通過構(gòu)造函數(shù)的參數(shù)來傳入。
          ???想了想好象只有第三種方法值得試試,但是后來想起來newItemTableItem是個對象,傳入以后卻不知道怎么轉(zhuǎn)換類型,呆了...
          ???最后做了個新的程序試了試,在新程序里是成功的,就是要把newItemTableItem在main函數(shù)外申明其為private static,但是在舊的程序中,編譯器是通過了,但是進行連接數(shù)據(jù)庫查詢的時候,出現(xiàn)“Fatal Exception...”的錯誤,當(dāng)時一下就蒙掉了!!完全一樣的,怎么會不成功。
          ???百般無奈以后,----當(dāng)然之前肯定是深思熟慮----終于腦海中閃出了傳說中的“靈感”!于是馬上把table也定義為private static......OK!???勝利總是來得那么突然,那瞬間的感覺就象90分鐘打進的金球...

          ???當(dāng)然到現(xiàn)在,我還沒找到確切的原因。只能用自己的話總結(jié)一下:(1)匿名內(nèi)部類中的方法是不能訪問其他方法中定義的變量的(包括實例對象),要訪問必須在類中將其定義為static類型。(2)TableItem是Table的子控件,要定義TableItem為static也要同時把Table定義為static類型。

          ???給自己一個任務(wù):研究JAVA的內(nèi)部類機制;研究SWT中父子控件關(guān)系的機制!

          ???看看《Thinking in JAVA》或許會是個不錯的選擇,當(dāng)然還有《The Definitive Guide to SWT and JFace》。

          ?

          posted @ 2007-01-15 02:41 J2S 閱讀(311) | 評論 (0)編輯 收藏

          2007年1月1日

          考完試了!

          昨天終于考完了!
          都大四了,還用最變態(tài)的老師(三大魔頭)來折磨我們,對于這學(xué)校真無語了......

          現(xiàn)在終于可以繼續(xù)我的自由學(xué)習(xí)之旅,以后一定每天上來更新blog。
          時間不多了,既然已經(jīng)飽受過往昏昏惑惑之疾、因循茍且之痛,那么現(xiàn)在就要珍惜分分秒秒,彌補差距。

          今天下午花了兩個小時把XML SPY教程學(xué)了一遍(沒想到這么快能搞定),我用的是2007,學(xué)的是2005,但基本上沒區(qū)別,進度還是蠻快的。最后估計那個xml schema文件沒寫好,最后用xslt轉(zhuǎn)換沒成功。不過晚上準(zhǔn)備再試一次,權(quán)當(dāng)做復(fù)習(xí)。
          以前都用記事本寫xml,現(xiàn)在用了xml spy感覺真是太好用了,尤其是xml數(shù)據(jù)與數(shù)據(jù)庫的互相轉(zhuǎn)換。而且還可以用工程來管理(還沒試呢),對于開發(fā)大一點的程序無疑方便了許多。

          晚上再準(zhǔn)備把struts那本書看看。

          對了,今天元旦,祝大家新年快樂,祈禱家人在新的一年里平平安安!

          posted @ 2007-01-01 16:42 J2S 閱讀(219) | 評論 (0)編輯 收藏

          2006年12月19日

          12月19日

          ?????????昨天搞了一個下午加晚上,配置eclipse3.2及其插件,最后太晚了沒上來更新blog。有幾點需要記一下:

          ??????(1)其實在links目錄里設(shè)置插件路徑的時候“//”也是可以用的,網(wǎng)上一般說用“/”或“\\”。以后只要記住一點:“\”(windows里的路徑格式)不能用就行了。

          ??????(2)myeclipse5.0以上必須配eclipse3.2;myeclipse4.0配eclipse3.0; 而myeclipse4.1才能配eclipse3.1。 昨天剛開始沒搞明白,給我的eclipse3.1.2下了一個myeclipse4.0和一個myeclipse5.1結(jié)果都不行,最后索性下了個最新的eclipse3.2.1,心想反正早晚都要升級干脆現(xiàn)在提前搞定算了。

          ??????(3)關(guān)于eclipse3.2.1的lomboz插件問題,在網(wǎng)上看了很多帖子(其實源帖就兩篇),總結(jié)如此:a) all-in-one版本里其實已經(jīng)包含了eclipse3.2了;b)兩種選擇:直接下載org.objectweb.lomboz-all-in-one-win32解壓縮即可;據(jù)說為了能支持GEF要分別下載這兩個插件lomboz-S-3.2RC2-200608081203lomboz-and-prereqs-S-3.2RC2-200608081203進行安裝。? 我最后還是選擇了第二種方法。
          ????????其實有了myeclipse,lomboz可以不用裝了,我想我只是為了多一種選擇吧,不知道這是不是我骨子里已經(jīng)開始傾向于開源了:)

          ??????(4)最后下了一個javasript的eclipse小插件,但是安裝不成功,不知道什么原因,反正以后再試吧...


          ??????最后,想說一點,其實昨天一天的工作是毫無技術(shù)含量的 ,而且現(xiàn)在時間這么緊,我應(yīng)該把一些更重要或更有價值的事情提到議程之前來,而不是跟自己過不去死鉆牛角尖。我知道這是性格做慫,但是希望以后自己更理智點更“聰明”點。時間對于我們這樣的人是最寶貴的!

          posted @ 2006-12-19 13:05 J2S 閱讀(342) | 評論 (0)編輯 收藏

          2006年12月18日

          初涉AJAX

          多數(shù) Web 應(yīng)用程序都使用請求/響應(yīng)模型從服務(wù)器上獲得完整的 HTML 頁面。常常是點擊一個按鈕,等待服務(wù)器響應(yīng),再點擊另一個按鈕,然后再等待,這樣一個反復(fù)的過程。有了 Ajax 和 XMLHttpRequest 對象,就可以使用不必讓用戶等待服務(wù)器響應(yīng)的請求/響應(yīng)模型了。本文中,Brett McLaughlin 介紹了如何創(chuàng)建能夠適應(yīng)不同瀏覽器的 XMLHttpRequest 實例,建立和發(fā)送請求,并響應(yīng)服務(wù)器。

          本系列的上一期文章(請參閱 參考資料 中的鏈接),我們介紹了 Ajax 應(yīng)用程序,考察了推動 Ajax 應(yīng)用程序的基本概念。其中的核心是很多您可能已經(jīng)了解的技術(shù):JavaScript、HTML 和 XHTML、一點動態(tài) HTML 以及 DOM(文檔對象模型)。本文將放大其中的一點,把目光放到具體的 Ajax 細節(jié)上。

          本文中,您將開始接觸最基本和基礎(chǔ)性的有關(guān) Ajax 的全部對象和編程方法:XMLHttpRequest 對象。該對象實際上僅僅是一個跨越所有 Ajax 應(yīng)用程序的公共線程,您可能已經(jīng)預(yù)料到,只有徹底理解該對象才能充分發(fā)揮編程的潛力。事實上,有時您會發(fā)現(xiàn),要正確地使用 XMLHttpRequest,顯然不能 使用 XMLHttpRequest。這到底是怎么回事呢?

          Web 2.0 一瞥

          在深入研究代碼之前首先看看最近的觀點 —— 一定要十分清楚 Web 2.0 這個概念。聽到 Web 2.0 這個詞的時候,應(yīng)該首先問一問 “Web 1.0 是什么?” 雖然很少聽人提到 Web 1.0,實際上它指的就是具有完全不同的請求和響應(yīng)模型的傳統(tǒng) Web。比如,到 Amazon.com 網(wǎng)站上點擊一個按鈕或者輸入搜索項。就會對服務(wù)器發(fā)送一個請求,然后響應(yīng)再返回到瀏覽器。該請求不僅僅是圖書和書目列表,而是另一個完整的 HTML 頁面。因此當(dāng) Web 瀏覽器用新的 HTML 頁面重繪時,可能會看到閃爍或抖動。事實上,通過看到的每個新頁面可以清晰地看到請求和響應(yīng)。

          Web 2.0(在很大程度上)消除了這種看得見的往復(fù)交互。比如訪問 Google Maps 或 Flickr 這樣的站點(到這些支持 Web 2.0 和 Ajax 站點的鏈接請參閱 參考資料)。比如在 Google Maps 上,您可以拖動地圖,放大和縮小,只有很少的重繪操作。當(dāng)然這里仍然有請求和響應(yīng),只不過都藏到了幕后。作為用戶,體驗更加舒適,感覺很像桌面應(yīng)用程序。這種新的感受和范型就是當(dāng)有人提到 Web 2.0 時您所體會到的。

          需要關(guān)心的是如何使這些新的交互成為可能。顯然,仍然需要發(fā)出請求和接收響應(yīng),但正是針對每次請求/響應(yīng)交互的 HTML 重繪造成了緩慢、笨拙的 Web 交互的感受。因此很清楚,我們需要一種方法使發(fā)送的請求和接收的響應(yīng)只 包含需要的數(shù)據(jù)而不是整個 HTML 頁面。惟一需要獲得整個新 HTML 頁面的時候就是希望用戶看到 新頁面的時候。

          但多數(shù)交互都是在已有頁面上增加細節(jié)、修改主體文本或者覆蓋原有數(shù)據(jù)。這些情況下,Ajax 和 Web 2.0 方法允許在不 更新整個 HTML 頁面的情況下發(fā)送和接收數(shù)據(jù)。對于那些經(jīng)常上網(wǎng)的人,這種能力可以讓您的應(yīng)用程序感覺更快、響應(yīng)更及時,讓他們不時地光顧您的網(wǎng)站。







          XMLHttpRequest 簡介

          要真正實現(xiàn)這種絢麗的奇跡,必須非常熟悉一個 JavaScript 對象,即 XMLHttpRequest。這個小小的對象實際上已經(jīng)在幾種瀏覽器中存在一段時間了,它是本專欄今后幾個月中要介紹的 Web 2.0、Ajax 和大部分其他內(nèi)容的核心。為了讓您快速地大體了解它,下面給出將要用于該對象的很少的幾個 方法和屬性。

          • open():建立到服務(wù)器的新請求。
          • send():向服務(wù)器發(fā)送請求。
          • abort():退出當(dāng)前請求。
          • readyState:提供當(dāng)前 HTML 的就緒狀態(tài)。
          • responseText:服務(wù)器返回的請求響應(yīng)文本。

          如果不了解這些(或者其中的任何 一個),您也不用擔(dān)心,后面幾篇文章中我們將介紹每個方法和屬性。現(xiàn)在應(yīng)該 了解的是,明確用 XMLHttpRequest 做什么。要注意這些方法和屬性都與發(fā)送請求及處理響應(yīng)有關(guān)。事實上,如果看到 XMLHttpRequest 的所有方法和屬性,就會發(fā)現(xiàn)它們都 與非常簡單的請求/響應(yīng)模型有關(guān)。顯然,我們不會遇到特別新的 GUI 對象或者創(chuàng)建用戶交互的某種超極神秘的方法,我們將使用非常簡單的請求和非常簡單的響應(yīng)。聽起來似乎沒有多少吸引力,但是用好該對象可以徹底改變您的應(yīng)用程序。

          簡單的 new

          首先需要創(chuàng)建一個新變量并賦給它一個 XMLHttpRequest 對象實例。這在 JavaScript 中很簡單,只要對該對象名使用 new 關(guān)鍵字即可,如 清單 1 所示。



          清單 1. 創(chuàng)建新的 XMLHttpRequest 對象
          <script language="javascript" type="text/javascript">
                                  var request = new XMLHttpRequest();
                                  </script>
                                  

          不難吧?記住,JavaScript 不要求指定變量類型,因此不需要像 清單 2 那樣做(在 Java 語言中可能需要這樣)。



          清單 2. 創(chuàng)建 XMLHttpRequest 的 Java 偽代碼
          XMLHttpRequest request = new XMLHttpRequest();
                                  

          因此在 JavaScript 中用 var 創(chuàng)建一個變量,給它一個名字(如 “request”),然后賦給它一個新的 XMLHttpRequest 實例。此后就可以在函數(shù)中使用該對象了。

          錯誤處理

          在實際上各種事情都可能出錯,而上面的代碼沒有提供任何錯誤處理。較好的辦法是創(chuàng)建該對象,并在出現(xiàn)問題時優(yōu)雅地退出。比如,任何較早的瀏覽器(不論您是否相信,仍然有人在使用老版本的 Netscape Navigator)都不支持 XMLHttpRequest,您需要讓這些用戶知道有些地方出了問題。清單 3 說明如何創(chuàng)建該對象,以便在出現(xiàn)問題的時候發(fā)出 JavaScript 警告。



          清單 3. 創(chuàng)建具有錯誤處理能力的 XMLHttpRequest
          <script language="javascript" type="text/javascript">
                                  var request = false;
                                  try {
                                  request = new XMLHttpRequest();
                                  } catch (failed) {
                                  request = false;
                                  }
                                  if (!request)
                                  alert("Error initializing XMLHttpRequest!");
                                  </script>
                                  

          一定要理解這些步驟:

          1. 創(chuàng)建一個新變量 request 并賦值 false。后面將使用 false 作為判定條件,它表示還沒有創(chuàng)建 XMLHttpRequest 對象。
          2. 增加 try/catch 塊:
            1. 嘗試創(chuàng)建 XMLHttpRequest 對象。
            2. 如果失敗(catch (failed))則保證 request 的值仍然為 false。
          3. 檢查 request 是否仍為 false(如果一切正常就不會是 false)。
          4. 如果出現(xiàn)問題(request 是 false)則使用 JavaScript 警告通知用戶出現(xiàn)了問題。

          代碼非常簡單,對大多數(shù) JavaScript 和 Web 開發(fā)人員來說,真正理解它要比讀寫代碼花更長的時間。現(xiàn)在已經(jīng)得到了一段帶有錯誤檢查的 XMLHttpRequest 對象創(chuàng)建代碼,還可以告訴您哪兒出了問題。

          應(yīng)付 Microsoft

          看起來似乎一切良好,至少在用 Internet Explorer 試驗這些代碼之前是這樣的。如果這樣試驗的話,就會看到 圖 1 所示的糟糕情形。



          圖 1. Internet Explorer 報告錯誤
          Internet Explorer 報告錯誤
          Microsoft 參與了嗎?
          關(guān)于 Ajax 和 Microsoft 對該領(lǐng)域不斷增長的興趣和參與已經(jīng)有很多文章進行了介紹。事實上,據(jù)說 Microsoft 最新版本的 Internet Explorer —— version 7.0,將在 2006 年下半年推出 —— 將開始直接支持 XMLHttpRequest,讓您使用 new 關(guān)鍵字代替所有的 Msxml2.XMLHTTP 創(chuàng)建代碼。但不要太激動,仍然需要支持舊的瀏覽器,因此跨瀏覽器代碼不會很快消失。

          顯然有什么地方不對勁,而 Internet Explorer 很難說是一種過時的瀏覽器,因為全世界有 70% 在使用 Internet Explorer。換句話說,如果不支持 Microsoft 和 Internet Explorer 就不會受到 Web 世界的歡迎!因此我們需要采用不同的方法處理 Microsoft 瀏覽器。

          經(jīng)驗證發(fā)現(xiàn) Microsoft 支持 Ajax,但是其 XMLHttpRequest 版本有不同的稱呼。事實上,它將其稱為幾種 不同的東西。如果使用較新版本的 Internet Explorer,則需要使用對象 Msxml2.XMLHTTP,而較老版本的 Internet Explorer 則使用 Microsoft.XMLHTTP。我們需要支持這兩種對象類型(同時還要支持非 Microsoft 瀏覽器)。請看看 清單 4,它在前述代碼的基礎(chǔ)上增加了對 Microsoft 的支持。



          清單 4. 增加對 Microsoft 瀏覽器的支持
          <script language="javascript" type="text/javascript">
                                  var request = false;
                                  try {
                                  request = new XMLHttpRequest();
                                  } catch (trymicrosoft) {
                                  try {
                                  request = new ActiveXObject("Msxml2.XMLHTTP");
                                  } catch (othermicrosoft) {
                                  try {
                                  request = new ActiveXObject("Microsoft.XMLHTTP");
                                  } catch (failed) {
                                  request = false;
                                  }
                                  }
                                  }
                                  if (!request)
                                  alert("Error initializing XMLHttpRequest!");
                                  </script>
                                  

          很容易被這些花括號迷住了眼睛,因此下面分別介紹每一步:

          1. 創(chuàng)建一個新變量 request 并賦值 false。使用 false 作為判斷條件,它表示還沒有創(chuàng)建 XMLHttpRequest 對象。
          2. 增加 try/catch 塊:
            1. 嘗試創(chuàng)建 XMLHttpRequest 對象。
            2. 如果失敗(catch (trymicrosoft)):
              1. 嘗試使用較新版本的 Microsoft 瀏覽器創(chuàng)建 Microsoft 兼容的對象(Msxml2.XMLHTTP)。
              2. 如果失敗(catch (othermicrosoft))嘗試使用較老版本的 Microsoft 瀏覽器創(chuàng)建 Microsoft 兼容的對象(Microsoft.XMLHTTP)。
            3. 如果失敗(catch (failed))則保證 request 的值仍然為 false。
          3. 檢查 request 是否仍然為 false(如果一切順利就不會是 false)。
          4. 如果出現(xiàn)問題(request 是 false)則使用 JavaScript 警告通知用戶出現(xiàn)了問題。

          這樣修改代碼之后再使用 Internet Explorer 試驗,就應(yīng)該看到已經(jīng)創(chuàng)建的表單(沒有錯誤消息)。我實驗的結(jié)果如 圖 2 所示。



          圖 2. Internet Explorer 正常工作
          Internet Explorer 正常工作

          靜態(tài)與動態(tài)

          再看一看清單 134,注意,所有這些代碼都直接嵌套在 script 標(biāo)記中。像這種不放到方法或函數(shù)體中的 JavaScript 代碼稱為靜態(tài) JavaScript。就是說代碼是在頁面顯示給用戶之前的某個時候運行。(雖然根據(jù)規(guī)范不能完全精確地 知道這些代碼何時運行對瀏覽器有什么影響,但是可以保證這些代碼在用戶能夠與頁面交互之前運行。)這也是多數(shù) Ajax 程序員創(chuàng)建 XMLHttpRequest 對象的一般方式。

          就是說,也可以像 清單 5 那樣將這些代碼放在一個方法中。



          清單 5. 將 XMLHttpRequest 創(chuàng)建代碼移動到方法中
          <script language="javascript" type="text/javascript">
                                  var request;
                                  function createRequest() {
                                  try {
                                  request = new XMLHttpRequest();
                                  } catch (trymicrosoft) {
                                  try {
                                  request = new ActiveXObject("Msxml2.XMLHTTP");
                                  } catch (othermicrosoft) {
                                  try {
                                  request = new ActiveXObject("Microsoft.XMLHTTP");
                                  } catch (failed) {
                                  request = false;
                                  }
                                  }
                                  }
                                  if (!request)
                                  alert("Error initializing XMLHttpRequest!");
                                  }
                                  </script>
                                  

          如果按照這種方式編寫代碼,那么在處理 Ajax 之前需要調(diào)用該方法。因此還需要 清單 6 這樣的代碼。



          清單 6. 使用 XMLHttpRequest 的創(chuàng)建方法
          <script language="javascript" type="text/javascript">
                                  var request;
                                  function createRequest() {
                                  try {
                                  request = new XMLHttpRequest();
                                  } catch (trymicrosoft) {
                                  try {
                                  request = new ActiveXObject("Msxml2.XMLHTTP");
                                  } catch (othermicrosoft) {
                                  try {
                                  request = new ActiveXObject("Microsoft.XMLHTTP");
                                  } catch (failed) {
                                  request = false;
                                  }
                                  }
                                  }
                                  if (!request)
                                  alert("Error initializing XMLHttpRequest!");
                                  }
                                  function getCustomerInfo() {
                                  createRequest();
                                  // Do something with the request variable
                                  }
                                  </script>
                                  

          此代碼惟一的問題是推遲了錯誤通知,這也是多數(shù) Ajax 程序員不采用這一方法的原因。假設(shè)一個復(fù)雜的表單有 10 或 15 個字段、選擇框等,當(dāng)用戶在第 14 個字段(按照表單順序從上到下)輸入文本時要激活某些 Ajax 代碼。這時候運行 getCustomerInfo() 嘗試創(chuàng)建一個 XMLHttpRequest 對象,但(對于本例來說)失敗了。然后向用戶顯示一條警告,明確地告訴他們不能使用該應(yīng)用程序。但用戶已經(jīng)花費了很多時間在表單中輸入數(shù)據(jù)!這是非常令人討厭的,而討厭顯然不會吸引用戶再次訪問您的網(wǎng)站。

          如果使用靜態(tài) JavaScript,用戶在點擊頁面的時候很快就會看到錯誤信息。這樣也很煩人,是不是?可能令用戶錯誤地認(rèn)為您的 Web 應(yīng)用程序不能在他的瀏覽器上運行。不過,當(dāng)然要比他們花費了 10 分鐘輸入信息之后再顯示同樣的錯誤要好。因此,我建議編寫靜態(tài)的代碼,讓用戶盡可能早地發(fā)現(xiàn)問題。







          用 XMLHttpRequest 發(fā)送請求

          得到請求對象之后就可以進入請求/響應(yīng)循環(huán)了。記住,XMLHttpRequest 惟一的目的是讓您發(fā)送請求和接收響應(yīng)。其他一切都是 JavaScript、CSS 或頁面中其他代碼的工作:改變用戶界面、切換圖像、解釋服務(wù)器返回的數(shù)據(jù)。準(zhǔn)備好 XMLHttpRequest 之后,就可以向服務(wù)器發(fā)送請求了。

          歡迎使用沙箱

          Ajax 采用一種沙箱安全模型。因此,Ajax 代碼(具體來說就是 XMLHttpRequest 對象)只能對所在的同一個域發(fā)送請求。以后的文章中將進一步介紹安全和 Ajax,現(xiàn)在只要知道在本地機器上運行的代碼只能對本地機器上的服務(wù)器端腳本發(fā)送請求。如果讓 Ajax 代碼在 www.breakneckpizza.com 上運行,則必須 www.breakneck.com 中運行的腳本發(fā)送請求。

          設(shè)置服務(wù)器 URL

          首先要確定連接的服務(wù)器的 URL。這并不是 Ajax 的特殊要求,但仍然是建立連接所必需的,顯然現(xiàn)在您應(yīng)該知道如何構(gòu)造 URL 了。多數(shù)應(yīng)用程序中都會結(jié)合一些靜態(tài)數(shù)據(jù)和用戶處理的表單中的數(shù)據(jù)來構(gòu)造該 URL。比如,清單 7 中的 JavaScript 代碼獲取電話號碼字段的值并用其構(gòu)造 URL。



          清單 7. 建立請求 URL
          <script language="javascript" type="text/javascript">
                                  var request = false;
                                  try {
                                  request = new XMLHttpRequest();
                                  } catch (trymicrosoft) {
                                  try {
                                  request = new ActiveXObject("Msxml2.XMLHTTP");
                                  } catch (othermicrosoft) {
                                  try {
                                  request = new ActiveXObject("Microsoft.XMLHTTP");
                                  } catch (failed) {
                                  request = false;
                                  }
                                  }
                                  }
                                  if (!request)
                                  alert("Error initializing XMLHttpRequest!");
                                  function getCustomerInfo() {
                                  var phone = document.getElementById("phone").value;
                                  var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
                                  }
                                  </script>
                                  

          這里沒有難懂的地方。首先,代碼創(chuàng)建了一個新變量 phone,并把 ID 為 “phone” 的表單字段的值賦給它。清單 8 展示了這個表單的 XHTML,其中可以看到 phone 字段及其 id 屬性。



          清單 8. Break Neck Pizza 表單
           <body>
                                  <p><img src="breakneck-logo_4c.gif" alt="Break Neck Pizza" /></p>
                                  <form action="POST">
                                  <p>Enter your phone number:
                                  <input type="text" size="14" name="phone" id="phone"
                                  onChange="getCustomerInfo();" />
                                  </p>
                                  <p>Your order will be delivered to:</p>
                                  <div id="address"></div>
                                  <p>Type your order in here:</p>
                                  <p><textarea name="order" rows="6" cols="50" id="order"></textarea></p>
                                  <p><input type="submit" value="Order Pizza" id="submit" /></p>
                                  </form>
                                  </body>
                                  

          還要注意,當(dāng)用戶輸入電話號碼或者改變電話號碼時,將觸發(fā) 清單 8 所示的 getCustomerInfo() 方法。該方法取得電話號碼并構(gòu)造存儲在 url 變量中的 URL 字符串。記住,由于 Ajax 代碼是沙箱型的,因而只能連接到同一個域,實際上 URL 中不需要域名。該例中的腳本名為 /cgi-local/lookupCustomer.php。最后,電話號碼作為 GET 參數(shù)附加到該腳本中:"phone=" + escape(phone)。

          如果以前沒用見過 escape() 方法,它用于轉(zhuǎn)義不能用明文正確發(fā)送的任何字符。比如,電話號碼中的空格將被轉(zhuǎn)換成字符 %20,從而能夠在 URL 中傳遞這些字符。

          可以根據(jù)需要添加任意多個參數(shù)。比如,如果需要增加另一個參數(shù),只需要將其附加到 URL 中并用 “與”(&)字符分開 [第一個參數(shù)用問號(?)和腳本名分開]。

          打開請求

          open() 是打開嗎?
          Internet 開發(fā)人員對 open() 方法到底做什么沒有達成一致。但它實際上并不是 打開一個請求。如果監(jiān)控 XHTML/Ajax 頁面及其連接腳本之間的網(wǎng)絡(luò)和數(shù)據(jù)傳遞,當(dāng)調(diào)用 open() 方法時將看不到任何通信。不清楚為何選用了這個名字,但顯然不是一個好的選擇。

          有了要連接的 URL 后就可以配置請求了。可以用 XMLHttpRequest 對象的 open() 方法來完成。該方法有五個參數(shù):

          • request-type:發(fā)送請求的類型。典型的值是 GET 或 POST,但也可以發(fā)送 HEAD 請求。
          • url:要連接的 URL。
          • asynch:如果希望使用異步連接則為 true,否則為 false。該參數(shù)是可選的,默認(rèn)為 true。
          • username:如果需要身份驗證,則可以在此指定用戶名。該可選參數(shù)沒有默認(rèn)值。
          • password:如果需要身份驗證,則可以在此指定口令。該可選參數(shù)沒有默認(rèn)值。

          通常使用其中的前三個參數(shù)。事實上,即使需要異步連接,也應(yīng)該指定第三個參數(shù)為 “true”。這是默認(rèn)值,但堅持明確指定請求是異步的還是同步的更容易理解。

          將這些結(jié)合起來,通常會得到 清單 9 所示的一行代碼。



          清單 9. 打開請求
             function getCustomerInfo() {
                                  var phone = document.getElementById("phone").value;
                                  var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
                                  request.open("GET", url, true);
                                  }
                                  

          一旦設(shè)置好了 URL,其他就簡單了。多數(shù)請求使用 GET 就夠了(后面的文章中將看到需要使用 POST 的情況),再加上 URL,這就是使用 open() 方法需要的全部內(nèi)容了。

          挑戰(zhàn)異步性

          本系列的后面一篇文章中,我將用很多時間編寫和使用異步代碼,但是您應(yīng)該明白為什么 open() 的最后一個參數(shù)這么重要。在一般的請求/響應(yīng)模型中,比如 Web 1.0,客戶機(瀏覽器或者本地機器上運行的代碼)向服務(wù)器發(fā)出請求。該請求是同步的,換句話說,客戶機等待服務(wù)器的響應(yīng)。當(dāng)客戶機等待的時候,至少會用某種形式通知您在等待:

          • 沙漏(特別是 Windows 上)。
          • 旋轉(zhuǎn)的皮球(通常在 Mac 機器上)。
          • 應(yīng)用程序基本上凍結(jié)了,然后過一段時間光標(biāo)變化了。

          這正是 Web 應(yīng)用程序讓人感到笨拙或緩慢的原因 —— 缺乏真正的交互性。按下按鈕時,應(yīng)用程序?qū)嶋H上變得不能使用,直到剛剛觸發(fā)的請求得到響應(yīng)。如果請求需要大量服務(wù)器處理,那么等待的時間可能很長(至少在這個多處理器、DSL 沒有等待的世界中是如此)。

          而異步請求不 等待服務(wù)器響應(yīng)。發(fā)送請求后應(yīng)用程序繼續(xù)運行。用戶仍然可以在 Web 表單中輸入數(shù)據(jù),甚至離開表單。沒有旋轉(zhuǎn)的皮球或者沙漏,應(yīng)用程序也沒有明顯的凍結(jié)。服務(wù)器悄悄地響應(yīng)請求,完成后告訴原來的請求者工作已經(jīng)結(jié)束(具體的辦法很快就會看到)。結(jié)果是,應(yīng)用程序感覺不 那么遲鈍或者緩慢,而是響應(yīng)迅速、交互性強,感覺快多了。這僅僅是 Web 2.0 的一部分,但它是很重要的一部分。所有老套的 GUI 組件和 Web 設(shè)計范型都不能克服緩慢、同步的請求/響應(yīng)模型。

          發(fā)送請求

          一旦用 open() 配置好之后,就可以發(fā)送請求了。幸運的是,發(fā)送請求的方法的名稱要比 open() 適當(dāng),它就是 send()。

          send() 只有一個參數(shù),就是要發(fā)送的內(nèi)容。但是在考慮這個方法之前,回想一下前面已經(jīng)通過 URL 本身發(fā)送過數(shù)據(jù)了:

          var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
                                  

          雖然可以使用 send() 發(fā)送數(shù)據(jù),但也能通過 URL 本身發(fā)送數(shù)據(jù)。事實上,GET 請求(在典型的 Ajax 應(yīng)用中大約占 80%)中,用 URL 發(fā)送數(shù)據(jù)要容易得多。如果需要發(fā)送安全信息或 XML,可能要考慮使用 send() 發(fā)送內(nèi)容(本系列的后續(xù)文章中將討論安全數(shù)據(jù)和 XML 消息)。如果不需要通過 send() 傳遞數(shù)據(jù),則只要傳遞 null 作為該方法的參數(shù)即可。因此您會發(fā)現(xiàn)在本文中的例子中只需要這樣發(fā)送請求(參見 清單 10)。



          清單 10. 發(fā)送請求
             function getCustomerInfo() {
                                  var phone = document.getElementById("phone").value;
                                  var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
                                  request.open("GET", url, true);
                                  request.send(null);
                                  }
                                  

          指定回調(diào)方法

          現(xiàn)在我們所做的只有很少一點是新的、革命性的或異步的。必須承認(rèn),open() 方法中 “true” 這個小小的關(guān)鍵字建立了異步請求。但是除此之外,這些代碼與用 Java servlet 及 JSP、PHP 或 Perl 編程沒有什么兩樣。那么 Ajax 和 Web 2.0 最大的秘密是什么呢?秘密就在于 XMLHttpRequest 的一個簡單屬性 onreadystatechange。

          首先一定要理解這些代碼中的流程(如果需要請回顧 清單 10)。建立其請求然后發(fā)出請求。此外,因為是異步請求,所以 JavaScript 方法(例子中的 getCustomerInfo())不會等待服務(wù)器。因此代碼將繼續(xù)執(zhí)行,就是說,將退出該方法而把控制返回給表單。用戶可以繼續(xù)輸入信息,應(yīng)用程序不會等待服務(wù)器。

          這就提出了一個有趣的問題:服務(wù)器完成了請求之后會發(fā)生什么?答案是什么也不發(fā)生,至少對現(xiàn)在的代碼而言如此!顯然這樣不行,因此服務(wù)器在完成通過 XMLHttpRequest 發(fā)送給它的請求處理之后需要某種指示說明怎么做。

          在 JavaScript 中引用函數(shù)
          JavaScript 是一種弱類型的語言,可以用變量引用任何東西。因此如果聲明了一個函數(shù) updatePage(),JavaScript 也將該函數(shù)名看作是一個變量。換句話說,可用變量名 updatePage 在代碼中引用函數(shù)。

          現(xiàn)在 onreadystatechange 屬性該登場了。該屬性允許指定一個回調(diào)函數(shù)。回調(diào)允許服務(wù)器(猜得到嗎?)反向調(diào)用 Web 頁面中的代碼。它也給了服務(wù)器一定程度的控制權(quán),當(dāng)服務(wù)器完成請求之后,會查看 XMLHttpRequest 對象,特別是 onreadystatechange 屬性。然后調(diào)用該屬性指定的任何方法。之所以稱為回調(diào)是因為服務(wù)器向網(wǎng)頁發(fā)起調(diào)用,無論網(wǎng)頁本身在做什么。比方說,可能在用戶坐在椅子上手沒有碰鍵盤的時候調(diào)用該方法,但是也可能在用戶輸入、移動鼠標(biāo)、滾動屏幕或者點擊按鈕時調(diào)用該方法。它并不關(guān)心用戶在做什么。

          這就是稱之為異步的原因:用戶在一層上操作表單,而在另一層上服務(wù)器響應(yīng)請求并觸發(fā) onreadystatechange 屬性指定的回調(diào)方法。因此需要像 清單 11 一樣在代碼中指定該方法。



          清單 11. 設(shè)置回調(diào)方法
             function getCustomerInfo() {
                                  var phone = document.getElementById("phone").value;
                                  var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
                                  request.open("GET", url, true);
                                  request.onreadystatechange = updatePage;
                                  request.send(null);
                                  }
                                  

          需要特別注意的是該屬性在代碼中設(shè)置的位置 —— 它是在調(diào)用 send() 之前 設(shè)置的。發(fā)送請求之前必須設(shè)置該屬性,這樣服務(wù)器在回答完成請求之后才能查看該屬性。現(xiàn)在剩下的就只有編寫 updatePage() 方法了,這是本文最后一節(jié)要討論的重點。







          處理服務(wù)器響應(yīng)

          發(fā)送請求,用戶高興地使用 Web 表單(同時服務(wù)器在處理請求),而現(xiàn)在服務(wù)器完成了請求處理。服務(wù)器查看 onreadystatechange 屬性確定要調(diào)用的方法。除此以外,可以將您的應(yīng)用程序看作其他應(yīng)用程序一樣,無論是否異步。換句話說,不一定要采取特殊的動作編寫響應(yīng)服務(wù)器的方法,只需要改變表單,讓用戶訪問另一個 URL 或者做響應(yīng)服務(wù)器需要的任何事情。這一節(jié)我們重點討論對服務(wù)器的響應(yīng)和一種典型的動作 —— 即時改變用戶看到的表單中的一部分。

          回調(diào)和 Ajax

          現(xiàn)在我們已經(jīng)看到如何告訴服務(wù)器完成后應(yīng)該做什么:將 XMLHttpRequest 對象的 onreadystatechange 屬性設(shè)置為要運行的函數(shù)名。這樣,當(dāng)服務(wù)器處理完請求后就會自動調(diào)用該函數(shù)。也不需要擔(dān)心該函數(shù)的任何參數(shù)。我們從一個簡單的方法開始,如 清單 12 所示。



          清單 12. 回調(diào)方法的代碼
          <script language="javascript" type="text/javascript">
                                  var request = false;
                                  try {
                                  request = new XMLHttpRequest();
                                  } catch (trymicrosoft) {
                                  try {
                                  request = new ActiveXObject("Msxml2.XMLHTTP");
                                  } catch (othermicrosoft) {
                                  try {
                                  request = new ActiveXObject("Microsoft.XMLHTTP");
                                  } catch (failed) {
                                  request = false;
                                  }
                                  }
                                  }
                                  if (!request)
                                  alert("Error initializing XMLHttpRequest!");
                                  function getCustomerInfo() {
                                  var phone = document.getElementById("phone").value;
                                  var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
                                  request.open("GET", url, true);
                                  request.onreadystatechange = updatePage;
                                  request.send(null);
                                  }
                                  function updatePage() {
                                  alert("Server is done!");
                                  }
                                  </script>
                                  

          它僅僅發(fā)出一些簡單的警告,告訴您服務(wù)器什么時候完成了任務(wù)。在自己的網(wǎng)頁中試驗這些代碼,然后在瀏覽器中打開(如果希望查看該例中的 XHTML,請參閱 清單 8)。輸入電話號碼然后離開該字段,將看到一個彈出的警告窗口(如 圖 3 所示),但是點擊 OK 又出現(xiàn)了……



          圖 3. 彈出警告的 Ajax 代碼
          彈出警告的 Ajax 代碼

          根據(jù)瀏覽器的不同,在表單停止彈出警告之前會看到兩次、三次甚至四次警告。這是怎么回事呢?原來我們還沒有考慮 HTTP 就緒狀態(tài),這是請求/響應(yīng)循環(huán)中的一個重要部分。

          HTTP 就緒狀態(tài)

          前面提到,服務(wù)器在完成請求之后會在 XMLHttpRequest 的 onreadystatechange 屬性中查找要調(diào)用的方法。這是真的,但還不完整。事實上,每當(dāng) HTTP 就緒狀態(tài)改變時它都會調(diào)用該方法。這意味著什么呢?首先必須理解 HTTP 就緒狀態(tài)。

          HTTP 就緒狀態(tài)表示請求的狀態(tài)或情形。它用于確定該請求是否已經(jīng)開始、是否得到了響應(yīng)或者請求/響應(yīng)模型是否已經(jīng)完成。它還可以幫助確定讀取服務(wù)器提供的響應(yīng)文本或數(shù)據(jù)是否安全。在 Ajax 應(yīng)用程序中需要了解五種就緒狀態(tài):

          • 0:請求沒有發(fā)出(在調(diào)用 open() 之前)。
          • 1:請求已經(jīng)建立但還沒有發(fā)出(調(diào)用 send() 之前)。
          • 2:請求已經(jīng)發(fā)出正在處理之中(這里通常可以從響應(yīng)得到內(nèi)容頭部)。
          • 3:請求已經(jīng)處理,響應(yīng)中通常有部分?jǐn)?shù)據(jù)可用,但是服務(wù)器還沒有完成響應(yīng)。
          • 4:響應(yīng)已完成,可以訪問服務(wù)器響應(yīng)并使用它。

          與大多數(shù)跨瀏覽器問題一樣,這些就緒狀態(tài)的使用也不盡一致。您也許期望任務(wù)就緒狀態(tài)從 0 到 1、2、3 再到 4,但實際上很少是這種情況。一些瀏覽器從不報告 0 或 1 而直接從 2 開始,然后是 3 和 4。其他瀏覽器則報告所有的狀態(tài)。還有一些則多次報告就緒狀態(tài) 1。在上一節(jié)中看到,服務(wù)器多次調(diào)用 updatePage(),每次調(diào)用都會彈出警告框 —— 可能和預(yù)期的不同!

          對于 Ajax 編程,需要直接處理的惟一狀態(tài)就是就緒狀態(tài) 4,它表示服務(wù)器響應(yīng)已經(jīng)完成,可以安全地使用響應(yīng)數(shù)據(jù)了。基于此,回調(diào)方法中的第一行應(yīng)該如 清單 13 所示。



          清單 13. 檢查就緒狀態(tài)
             function updatePage() {
                                  if (request.readyState == 4)
                                  alert("Server is done!");
                                  }
                                  

          修改后就可以保證服務(wù)器的處理已經(jīng)完成。嘗試運行新版本的 Ajax 代碼,現(xiàn)在就會看到與預(yù)期的一樣,只顯示一次警告信息了。

          HTTP 狀態(tài)碼

          雖然 清單 13 中的代碼看起來似乎不錯,但是還有一個問題 —— 如果服務(wù)器響應(yīng)請求并完成了處理但是報告了一個錯誤怎么辦?要知道,服務(wù)器端代碼應(yīng)該明白它是由 Ajax、JSP、普通 HTML 表單或其他類型的代碼調(diào)用的,但只能使用傳統(tǒng)的 Web 專用方法報告信息。而在 Web 世界中,HTTP 代碼可以處理請求中可能發(fā)生的各種問題。

          比方說,您肯定遇到過輸入了錯誤的 URL 請求而得到 404 錯誤碼的情形,它表示該頁面不存在。這僅僅是 HTTP 請求能夠收到的眾多錯誤碼中的一種(完整的狀態(tài)碼列表請參閱 參考資料 中的鏈接)。表示所訪問數(shù)據(jù)受到保護或者禁止訪問的 403 和 401 也很常見。無論哪種情況,這些錯誤碼都是從完成的響應(yīng) 得到的。換句話說,服務(wù)器履行了請求(即 HTTP 就緒狀態(tài)是 4)但是沒有返回客戶機預(yù)期的數(shù)據(jù)。

          因此除了就緒狀態(tài)外,還需要檢查 HTTP 狀態(tài)。我們期望的狀態(tài)碼是 200,它表示一切順利。如果就緒狀態(tài)是 4 而且狀態(tài)碼是 200,就可以處理服務(wù)器的數(shù)據(jù)了,而且這些數(shù)據(jù)應(yīng)該就是要求的數(shù)據(jù)(而不是錯誤或者其他有問題的信息)。因此還要在回調(diào)方法中增加狀態(tài)檢查,如 清單 14 所示。



          清單 14. 檢查 HTTP 狀態(tài)碼
             function updatePage() {
                                  if (request.readyState == 4)
                                  if (request.status == 200)
                                  alert("Server is done!");
                                  }
                                  

          為了增加更健壯的錯誤處理并盡量避免過于復(fù)雜,可以增加一兩個狀態(tài)碼檢查,請看一看 清單 15 中修改后的 updatePage() 版本。



          清單 15. 增加一點錯誤檢查
             function updatePage() {
                                  if (request.readyState == 4)
                                  if (request.status == 200)
                                  alert("Server is done!");
                                  else if (request.status == 404)
                                  alert("Request URL does not exist");
                                  else
                                  alert("Error: status code is " + request.status);
                                  }
                                  

          現(xiàn)在將 getCustomerInfo() 中的 URL 改為不存在的 URL 看看會發(fā)生什么。應(yīng)該會看到警告信息說明要求的 URL 不存在 —— 好極了!很難處理所有的錯誤條件,但是這一小小的改變能夠涵蓋典型 Web 應(yīng)用程序中 80% 的問題。

          讀取響應(yīng)文本

          現(xiàn)在可以確保請求已經(jīng)處理完成(通過就緒狀態(tài)),服務(wù)器給出了正常的響應(yīng)(通過狀態(tài)碼),最后我們可以處理服務(wù)器返回的數(shù)據(jù)了。返回的數(shù)據(jù)保存在 XMLHttpRequest 對象的 responseText 屬性中。

          關(guān)于 responseText 中的文本內(nèi)容,比如格式和長度,有意保持含糊。這樣服務(wù)器就可以將文本設(shè)置成任何內(nèi)容。比方說,一種腳本可能返回逗號分隔的值,另一種則使用管道符(即 | 字符)分隔的值,還有一種則返回長文本字符串。何去何從由服務(wù)器決定。

          在本文使用的例子中,服務(wù)器返回客戶的上一個訂單和客戶地址,中間用管道符分開。然后使用訂單和地址設(shè)置表單中的元素值,清單 16 給出了更新顯示內(nèi)容的代碼。



          清單 16. 處理服務(wù)器響應(yīng)
             function updatePage() {
                                  if (request.readyState == 4) {
                                  if (request.status == 200) {
                                  var response = request.responseText.split("|");
                                  document.getElementById("order").value = response[0];
                                  document.getElementById("address").innerHTML =
                                  response[1].replace(/\n/g, "
          "); } else alert("status is " + request.status); } }

          首先,得到 responseText 并使用 JavaScript split() 方法從管道符分開。得到的數(shù)組放到 response 中。數(shù)組中的第一個值 —— 上一個訂單 —— 用 response[0] 訪問,被設(shè)置為 ID 為 “order” 的字段的值。第二個值 response[1],即客戶地址,則需要更多一點處理。因為地址中的行用一般的行分隔符(“\n”字符)分隔,代碼中需要用 XHTML 風(fēng)格的行分隔符 <br /> 來代替。替換過程使用 replace() 函數(shù)和正則表達式完成。最后,修改后的文本作為 HTML 表單 div 中的內(nèi)部 HTML。結(jié)果就是表單突然用客戶信息更新了,如圖 4 所示。



          圖 4. 收到客戶數(shù)據(jù)后的 Break Neck 表單
          收到客戶數(shù)據(jù)后的 Break Neck 表單

          結(jié)束本文之前,我還要介紹 XMLHttpRequest 的另一個重要屬性 responseXML。如果服務(wù)器選擇使用 XML 響應(yīng)則該屬性包含(也許您已經(jīng)猜到)XML 響應(yīng)。處理 XML 響應(yīng)和處理普通文本有很大不同,涉及到解析、文檔對象模型(DOM)和其他一些問題。后面的文章中將進一步介紹 XML。但是因為 responseXML 通常和 responseText 一起討論,這里有必要提一提。對于很多簡單的 Ajax 應(yīng)用程序 responseText 就夠了,但是您很快就會看到通過 Ajax 應(yīng)用程序也能很好地處理 XML。







          結(jié)束語

          您可能對 XMLHttpRequest 感到有點厭倦了,我很少看到一整篇文章討論一個對象,特別是這種簡單的對象。但是您將在使用 Ajax 編寫的每個頁面和應(yīng)用程序中反復(fù)使用該對象。坦白地說,關(guān)于 XMLHttpRequest 還真有一些可說的內(nèi)容。下一期文章中將介紹如何在請求中使用 POST 及 GET,來設(shè)置請求中的內(nèi)容頭部和從服務(wù)器響應(yīng)讀取內(nèi)容頭部,理解如何在請求/響應(yīng)模型中編碼請求和處理 XML。

          再往后我們將介紹常見 Ajax 工具箱。這些工具箱實際上隱藏了本文所述的很多細節(jié),使得 Ajax 編程更容易。您也許會想,既然有這么多工具箱為何還要對底層的細節(jié)編碼。答案是,如果不知道應(yīng)用程序在做什么,就很難發(fā)現(xiàn)應(yīng)用程序中的問題。

          因此不要忽略這些細節(jié)或者簡單地瀏覽一下,如果便捷華麗的工具箱出現(xiàn)了錯誤,您就不必?fù)项^或者發(fā)送郵件請求支持了。如果了解如何直接使用 XMLHttpRequest,就會發(fā)現(xiàn)很容易調(diào)試和解決最奇怪的問題。只有讓其解決您的問題,工具箱才是好東西。

          因此請熟悉 XMLHttpRequest 吧。事實上,如果您有使用工具箱的 Ajax 代碼,可以嘗試使用 XMLHttpRequest 對象及其屬性和方法重新改寫。這是一種不錯的練習(xí),可以幫助您更好地理解其中的原理。

          posted @ 2006-12-18 00:32 J2S 閱讀(288) | 評論 (0)編輯 收藏

          SWT/JFace開發(fā)入門指南(十一)〈轉(zhuǎn)帖〉

          JFace中的工具條和菜單

          前一節(jié)中我們簡單介紹了一下 Action 。其實所謂的 Action 就是一個最常用的事件,舉個例子來說,對于一個按鈕來說它可以有多個事件,比如按鍵,焦點,鼠標(biāo),等等等等吧,但是實際上在使用程序的時候,我們最關(guān)心的,就是按下去這個按鈕會發(fā)生什么,這個其實就是所謂的 Action 。如果大家以前做過 swing/awt 變成的話,應(yīng)該對 Action 不會陌生。

          JFace 里面,一個 Action 可以對應(yīng)多個 GUI 對象,這些對象就是所謂的 Contribution Item 。比如我們在一般程序里面很常見的“文件”菜單,下面都會有“新建”,“保存”等等。同時我們可以在工具條上放置相應(yīng)的按鈕,那么這些都是有相同的功能,在 JFace 里面我們可以只寫一個 Action ,然后把它映射到不同的 ContributionItem 去,而不必為每個部件都寫一串處理事件。

          我們下面還是通過一個簡單的例子來說明,在 JFace 中怎么使用菜單和工具條這兩種最基本也是最有用的 Contribution Item

          我們這個程序?qū)懙煤苌担褪且粋€光禿禿的窗口上做了一個菜單和工具條按鈕,功能也只有一個,就是每次點一下,就彈出一個輸入框來問你名字是什么,然后顯示一個 Hello, xxx 之類的。

          首先我們還是來寫一個 Action 類:

          ?1?
          ?2?public?class?SayHiAction?extends?Action?{
          ?3?????private?Shell?shell;
          ?4?
          ?5?????public?SayHiAction(Shell?shell)?{
          ?6?????????super();
          ?7?????????this.shell?=?shell;
          ?8?????????this.setText("Say&Hi@Ctrl+H");
          ?9?????}
          10?
          11?????@Override
          12?????public?void?run()?{
          13?????????InputDialog?input?=?new?InputDialog(shell,?"Input?your?name",
          14?????????????????"Please?input?your?name?here:",?null,?null);
          15?????????if?(input.open()?==?Window.OK)?{
          16?????????????MessageDialog.openInformation(shell,?"Hello",?"Hello,?"
          17?????????????????????+?input.getValue()?+?"!");
          18?????????}
          19?
          20?????}
          21?
          22?}
          23?



          代碼段 17

          這只是一個很簡單的 Action 類,沒有太多可說的。

          然后我們創(chuàng)建一個 ApplicationWindow 類:

          ?1?
          ?2?public?class?Hiyou?extends?ApplicationWindow?{
          ?3?
          ?4?????private?SayHiAction?hiaction;
          ?5?????public?Hiyou(Shell?parentShell)?{
          ?6?????????super(parentShell);
          ?7?????????hiaction=new?SayHiAction(getShell());
          ?8?????????addMenuBar();
          ?9?????????addToolBar(SWT.FLAT?|?SWT.WRAP);
          10?????}
          11?
          12?????@Override
          13?????protected?ToolBarManager?createToolBarManager(int?style)?{
          14?????????ToolBarManager?toolbar=new?ToolBarManager();
          15?????????toolbar.add(hiaction);
          16?????????return?toolbar;
          17?????}
          18?
          19?????@Override
          20?????protected?MenuManager?createMenuManager()?{
          21?????????MenuManager?menubar=new?MenuManager();
          22?????????MenuManager?fileMenu=new?MenuManager("&File");
          23?????????fileMenu.add(hiaction);
          24?????????menubar.add(fileMenu);
          25?????????return?menubar;
          26?????}
          27?
          28?????/**
          29??????*?@param?args
          30??????*/
          31?????public?static?void?main(String[]?args)?{
          32?????????Hiyou?window=new?Hiyou(null);
          33?????????window.setBlockOnOpen(true);
          34?????????window.open();
          35?????????Display.getCurrent().dispose();
          36?????}
          37?
          38?}
          39?

          ?

          代碼段 18

          大家可能已經(jīng)注意到了,在這里面我們重載了 createMenuManager createToolBarManager 兩個方法,它們的用途就和名字一樣,一個是用來創(chuàng)建菜單的,一個是用來創(chuàng)建工具條的。重載了這兩個方法以后,通過在構(gòu)造函數(shù)中調(diào)用 addMenuBar addToolBar 讓工具條和菜單顯示出來。

          這里值得一提的是 MenuManager ToolBarManager 類,如果大家翻一下 API 文檔的話會發(fā)現(xiàn)它們都是所謂的 contribution manager (實現(xiàn)了 IConntributionManager 接口),你可以通過這些 contribution manager 來實現(xiàn)對特定組件的管理(添加刪除等等)。

          具體到菜單的創(chuàng)建,看了我們上面的代碼就很明白了,就直接調(diào)用相應(yīng) MenuManager add 方法把 action 添加上就可以了。 JFace 會自動找到這個 Action getText 方法設(shè)置菜單的文字。如果是有好幾層菜單,那么只要在重新 new 一個 MenuManager 添加到已有的 MenuManager 里面就可以了。就象前面代碼中的:

          menubar.add(fileMenu);



          至于工具條就更簡單了,創(chuàng)建一個 ToolBarManager 然后直接 add 對應(yīng)的 Action 就可以了。

          添加圖標(biāo)

          如果菜單只是文字還沒有什么,如果你的工具條都是文字是不是會顯得干巴巴的?其實只要我們?yōu)?/span> Action 設(shè)置 ImageDescriptor 就可以了,比如你可以自己畫一個圖標(biāo)保存到 Action 的包下面(我畫了一個 hi.gif ),然后把 Action 的構(gòu)造函數(shù)改寫成這樣:

          public ?SayHiAction(Shell?shell)?{
          ????????
          super ();
          ????????
          this .shell? = ?shell;
          ????????
          this .setText( " Say&Hi@Ctrl+H " );
          ????????
          this .setImageDescriptor(ImageDescriptor.createFromFile( this .getClass(),
          ????????????????
          " hi.gif " ));
          ????}



          大家注意最后一句話,就是為 action 設(shè)置圖標(biāo)的。然后再運行一下就會發(fā)現(xiàn)菜單和工具欄都有圖標(biāo)了。

          posted @ 2006-12-18 00:26 J2S 閱讀(348) | 評論 (0)編輯 收藏

          僅列出標(biāo)題  下一頁
          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(2)

          隨筆檔案

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 香格里拉县| 宁城县| 青阳县| 凤阳县| 泰州市| 东兴市| 安庆市| 峨眉山市| 治县。| 理塘县| 郑州市| 上蔡县| 大庆市| 福鼎市| 化隆| 阿拉善左旗| 临洮县| 临高县| 五大连池市| 无极县| 临湘市| 玉田县| 溆浦县| 德江县| 万全县| 社旗县| 乐山市| 甘谷县| 清水河县| 苍南县| 齐河县| 桂林市| 潼南县| 贵阳市| 邵阳县| 胶州市| 辽阳市| 黄骅市| 甘泉县| 威远县| 扬中市|