?? chapter13.htm
字號(hào):
mouseEnter(Event evt, int x, int y) 鼠標(biāo)從前不在組件上方,但目前在<br>
mouseExit(Event evt, int x, int y) 鼠標(biāo)曾經(jīng)位于組件上方,但目前不在<br>
<br>
當(dāng)我們處理特殊情況時(shí)——一個(gè)鼠標(biāo)事件,例如,它恰好是我們想得到的鼠標(biāo)事件存在的座標(biāo),我們將看到每個(gè)程序接收一個(gè)事件連同一些我們所需要的信息。有趣的是,當(dāng)組件的handleEvent()調(diào)用這些方法時(shí)(典型的事例),附加的自變量總是多余的因?yàn)樗鼈儼谑录?duì)象里。事實(shí)上,如果我們觀察component.handleEvent()的源代碼,我們能發(fā)現(xiàn)它顯然將增加的自變量抽出事件對(duì)象(這可能是考慮到在一些語言中無效率的編碼,但請(qǐng)記住Java的焦點(diǎn)是安全的,不必?fù)?dān)心。)試驗(yàn)對(duì)我們表明這些事件事實(shí)上在被調(diào)用并且作為一個(gè)有趣的嘗試是值得創(chuàng)建一個(gè)過載每個(gè)方法的程序片,(action()的過載在本章的其它地方)當(dāng)事件發(fā)生時(shí)顯示它們的相關(guān)數(shù)據(jù)。<br>
這個(gè)例子同樣向我們展示了怎樣制造自己的按鈕對(duì)象,因?yàn)樗亲鳛槟繕?biāo)的所有事件權(quán)益來使用。我可能會(huì)首先(也是必須的)假設(shè)制造一個(gè)新的按鈕,我們從按鈕處繼承。但它并不能運(yùn)行。取而代之的是,我們從畫布組件處(一個(gè)非常普通組件)繼承,并在其上不使用paint()方法畫出一個(gè)按鈕。正如我們所看到的,自從一些代碼混入到畫按鈕中去,按鈕根本就不運(yùn)行,這實(shí)在是太糟糕了。(如果您不相信我,試圖在例子中為畫布組件交換按鈕,請(qǐng)記住調(diào)用稱為super的基礎(chǔ)類構(gòu)建器。我們會(huì)看到按鈕不會(huì)被畫出,事件也不會(huì)被處理。)<br>
myButton類是明確說明的:它只和一個(gè)自動(dòng)事件(AutoEvent)“父窗口”一起運(yùn)行(父窗口不是一個(gè)基礎(chǔ)類,它是按鈕創(chuàng)建和存在的窗口。)。通過這個(gè)知識(shí),myButton可能進(jìn)入到父窗口并且處理它的文字字段,必然就能將狀態(tài)信息寫入到父窗口的字段里。當(dāng)然這是一種非常有限的解決方法,myButton僅能在連結(jié)AutoEvent時(shí)被使用。這種代碼有時(shí)稱為“高度結(jié)合”。但是,制造myButton更需要很多的不是為例子(和可能為我們將寫的一些程序片)擔(dān)保的努力。再者,請(qǐng)注意下面的代碼使用了Java
1.1版不支持的API。<br>
<br>
621-624頁程序<br>
<br>
我們可以看到構(gòu)建器使用利用自變量同名的方法,所以自變量被賦值,并且使用this來區(qū)分:<br>
this.label = label;<br>
paint()方法由簡(jiǎn)單的開始:它用按鈕的顏色填充了一個(gè)“圓角矩形”,然后畫了一個(gè)黑線圍繞它。請(qǐng)注意size()的使用決定了組件的寬度和長(zhǎng)度(當(dāng)然,是像素)。這之后,paint()看起來非常的復(fù)雜,因?yàn)橛写罅康念A(yù)測(cè)去計(jì)算出怎樣利用“font
metrics”集中按鈕的標(biāo)簽到按鈕里。我們能得到一個(gè)相當(dāng)好的關(guān)于繼續(xù)關(guān)注方法調(diào)用的主意,它將程序中那些相當(dāng)平凡的代碼挑出,當(dāng)我們想集中一個(gè)標(biāo)簽到一些組件里時(shí),我們正好可以對(duì)它進(jìn)行剪切和粘貼。<br>
您直到注意到AutoEvent類才能正確地理解keyDown(),keyUp()及其它方法的運(yùn)行。這包含一個(gè)Hashtable(譯者注:散列表)去控制字符串來描述關(guān)于事件處理的事件和TextField類型。當(dāng)然,這些能被靜態(tài)的創(chuàng)建而不是放入Hashtable但我認(rèn)為您會(huì)同意它是更容易使用和改變的。特別是,如果我們需要在AutoEvent中增加或刪除一個(gè)新的事件類型,我們只需要簡(jiǎn)單地在事件列隊(duì)中增加或刪除一個(gè)字符串——所有的工作都自動(dòng)地完成了。<br>
我們查出在keyDown(),keyup()及其它方法中的字符串的位置回到myButton中。這些方法中的任何一個(gè)都用父句柄試圖回到父窗口。父類是一個(gè)AutoEvent,它包含Hashtable
h和get()方法,當(dāng)擁有特定的字符串時(shí),將對(duì)一個(gè)我們知道的TextField對(duì)象產(chǎn)生一個(gè)句柄(因此它被選派到那)。然后事件對(duì)象修改顯示在TextField中的字符串陳述。從我們可以真正注意到舉出的例子在我們的程序中運(yùn)行事件時(shí)以來,可以發(fā)現(xiàn)這個(gè)例子運(yùn)行起來頗為有趣的。<br>
<br>
13.14 程序片的局限<br>
出于安全緣故,程序片十分受到限制,并且有很多的事我們都不能做。您一般會(huì)問:程序片看起來能做什么,傳聞它又能做什么:擴(kuò)展瀏覽器中WEB頁的功能。自從作為一個(gè)網(wǎng)上沖浪者,我們從未真正想了解是否一個(gè)WEB頁來自友好的或者不友好的站點(diǎn),我們想要一些可以安全地行動(dòng)的代碼。所以我們可能會(huì)注意到大量的限制:<br>
(1)
一個(gè)程序片不能接觸到本地的磁盤。這意味著不能在本地磁盤上寫和讀,我們不想一個(gè)程序片通過WEB頁面閱讀和傳送重要的信息。寫是被禁止的,當(dāng)然,因?yàn)槟菍?huì)引起病毒的侵入。當(dāng)數(shù)字簽名生效時(shí),這些限制會(huì)被解除。<br>
(2) 程序片不能擁有菜單。(注意:這是規(guī)定在Swing中的)這可能會(huì)減少關(guān)于安全和關(guān)于程序簡(jiǎn)化的麻煩。我們可能會(huì)接到有關(guān)程序片協(xié)調(diào)利益以作為WEB頁面的一部分的通知;而我們通常不去注意程序片的范圍。這兒沒有幀和標(biāo)題條從菜單處彈出,出現(xiàn)的幀和標(biāo)題條是屬于WEB瀏覽器的。也許將來設(shè)計(jì)能被改變成允許我們將瀏覽器菜單和程序片菜單相結(jié)合起來——程序片可以影響它的環(huán)境將導(dǎo)致太危及整個(gè)系統(tǒng)的安全并使程序片過于的復(fù)雜。<br>
(3) 對(duì)話框是不被信任的。在Java中,對(duì)話框存在一些令人難解的地方。首先,它們不能正確地拒絕程序片,這實(shí)在是令人沮喪。如果我們從程序片彈出一個(gè)對(duì)話框,我們會(huì)在對(duì)話框上看到一個(gè)附上的消息框“不被信任的程序片”。這是因?yàn)樵诶碚撋希锌赡芷垓_用戶去考慮他們?cè)谕ㄟ^WEB同一個(gè)老顧客的本地應(yīng)用程序交易并且讓他們輸入他們的信用卡號(hào)。在看到AWT開發(fā)的那種GUI后,我們可能會(huì)難過地相信任何人都會(huì)被那種方法所愚弄。但程序片是一直附著在一個(gè)Web頁面上的,并可以在瀏覽器中看到,而對(duì)話框沒有這種依附關(guān)系,所以理論上是可能的。因此,我們很少會(huì)見到一個(gè)使用對(duì)話框的程序片。<br>
在較新的瀏覽器中,對(duì)受到信任的程序片來說,許多限制都被放寬了(受信任程序片由一個(gè)信任源認(rèn)證)。<br>
涉及程序片的開發(fā)時(shí),還有另一些問題需要考慮:<br>
■程序片不停地從一個(gè)適合不同類的單獨(dú)的服務(wù)器上下載。我們的瀏覽器能夠緩存程序片,但這沒有保證。在Java
1.1版中的一個(gè)改進(jìn)是JAR(Java ARchive)文件,它允許將所有的程序片組件(包括其它的類文件、圖像、聲音)一起打包到一個(gè)的能被單個(gè)服務(wù)器處理下載的壓縮文件。“數(shù)字簽字”(能校驗(yàn)類創(chuàng)建器)可有效地加入每個(gè)單獨(dú)的JAR文件。<br>
■因?yàn)榘踩矫娴木壒剩覀冏瞿承┕ぷ鞲永щy,例如訪問數(shù)據(jù)庫和發(fā)送電子郵件。另外,安全限制規(guī)則使訪問多個(gè)主機(jī)變得非常的困難,因?yàn)槊恳患露急仨毻ㄟ^WEB服務(wù)器路由,形成一個(gè)性能瓶頸,并且單一環(huán)節(jié)的出錯(cuò)都會(huì)導(dǎo)致整個(gè)處理的停止。<br>
■瀏覽器里的程序片不會(huì)擁有同樣的本地應(yīng)用程序運(yùn)行的控件類型。例如,自從用戶可以開關(guān)頁面以來,在程序片中不會(huì)擁有一個(gè)形式上的對(duì)話框。當(dāng)用戶對(duì)一個(gè)WEB頁面進(jìn)行改變或退出瀏覽器時(shí),對(duì)我們的程序片而言簡(jiǎn)直是一場(chǎng)災(zāi)難——這時(shí)沒有辦法保存狀態(tài),所以如果我們?cè)谔幚砗筒僮髦袝r(shí),信息會(huì)被丟失。另外,當(dāng)我們離開一個(gè)WEB頁面時(shí),不同的瀏覽器會(huì)對(duì)我們的程序片做不同的操作,因此結(jié)果本來就是不確定的。<br>
<br>
13.14.1 程序片的優(yōu)點(diǎn)<br>
如果能容忍那些限制,那么程序片的一些優(yōu)點(diǎn)也是非常突出的,尤其是在我們構(gòu)建客戶/服務(wù)器應(yīng)用或者其它網(wǎng)絡(luò)應(yīng)用時(shí):<br>
■沒有安裝方面的爭(zhēng)議。程序片擁有真正的平臺(tái)獨(dú)立性(包括容易地播放聲音文件等能力)所以我們不需要針對(duì)不同的平臺(tái)修改代碼也不需要任何人根據(jù)安裝運(yùn)行任何的“tweaking”。事實(shí)上,安裝每次自動(dòng)地將WEB頁連同程序片一起,因此安靜、自動(dòng)地更新。在傳統(tǒng)的客戶機(jī)/服務(wù)器系統(tǒng)中,建立和安裝一個(gè)新版本的客戶端軟件簡(jiǎn)直就是一場(chǎng)惡夢(mèng)。<br>
■因?yàn)榘踩脑騽?chuàng)建在核心Java語言和程序片結(jié)構(gòu)中,我們不必?fù)?dān)心壞的代碼而導(dǎo)致毀壞某人的系統(tǒng)。這樣,連同前面的優(yōu)點(diǎn),可使用Java(可從JavaScript和VBScript中選擇客戶端的WEB編程工具)為所謂的Intrant(在公司內(nèi)部使用而不向Internet轉(zhuǎn)移的企業(yè)內(nèi)部網(wǎng)絡(luò))客戶機(jī)/服務(wù)器開發(fā)應(yīng)用程序。<br>
■由于程序片是自動(dòng)同HTML集成的,所以我們有一個(gè)內(nèi)建的獨(dú)立平臺(tái)文件系統(tǒng)去支持程序片。這是一個(gè)很有趣的方法,因?yàn)槲覀儜T于擁有程序文件的一部分而不是相反的擁有文件系統(tǒng)。<br>
<br>
13.15 視窗化應(yīng)用<br>
出于安全的緣故,我們會(huì)看到在程序片我們的行為非常的受到限制。我們真實(shí)地感到,程序片是被臨時(shí)地加入在WEB瀏覽器中的,因此,它的功能連同它的相關(guān)知識(shí),控件都必須加以限制。但是,我們希望Java能制造一個(gè)開窗口的程序去運(yùn)行一些事物,否則寧愿安放在一個(gè)WEB頁面上,并且也許我們希望它可以運(yùn)行一些可靠的應(yīng)用程序,以及夸張的實(shí)時(shí)便攜性。在這本書前面的章節(jié)中我們制造了一些命令行應(yīng)用程序,但在一些操作環(huán)境中(例如:Macintosh)沒有命令行。所以我們有很多的理由去利用Java創(chuàng)建一個(gè)設(shè)置窗口,非程序片的程序。這當(dāng)然是一個(gè)十分合理的要求。<br>
一個(gè)Java設(shè)置窗口應(yīng)用程序可以擁有菜單和對(duì)話框(這對(duì)一個(gè)程序片來說是不可能的和很困難的),可是如果我們使用一個(gè)老版本的Java,我們將會(huì)犧牲本地操作系統(tǒng)環(huán)境的外觀和感受。JFC/Swing庫允許我們制造一個(gè)保持原來操作系統(tǒng)環(huán)境的外觀和感受的應(yīng)用程序。如果我們想建立一個(gè)設(shè)置窗口應(yīng)用程序,它會(huì)合理地運(yùn)作,同樣,如果我們可以使用最新版本的Java并且集合所有的工具,我們就可以發(fā)布不會(huì)使用戶困惑的應(yīng)用程序。如果因?yàn)橐恍┰颍覀儽黄仁褂美习姹镜腏ava,請(qǐng)?jiān)跉囊越⒅匾脑O(shè)置窗口的應(yīng)用程序前仔細(xì)地考慮。<br>
<br>
13.15.1 菜單<br>
直接在程序片中安放一個(gè)菜單是不可能的(Java 1.0,Java1.1和Swing庫不允許),因?yàn)樗鼈兪轻槍?duì)應(yīng)用程序的。繼續(xù),如果您不相信我并且確定在程序片中可以合理地?fù)碛胁藛危敲茨梢匀ピ囼?yàn)一下。程序片中沒有setMenuBar()方法,而這種方法是附在菜單中的(我們會(huì)看到它可以合理地在程序片產(chǎn)生一個(gè)幀,并且?guī)藛危?lt;br>
有四種不同類型的MenuComponent(菜單組件),所有的菜單組件起源于抽象類:菜單條(我們可以在一個(gè)事件幀里擁有一個(gè)菜單條),菜單去支配一個(gè)單獨(dú)的下拉菜單或者子菜單、菜單項(xiàng)來說明菜單里一個(gè)單個(gè)的元素,以及起源于MenuItem,產(chǎn)生檢查標(biāo)志(checkmark)去顯示菜單項(xiàng)是否被選擇的CheckBoxMenuItem。<br>
不同的系統(tǒng)使用不同的資源,對(duì)Java和AWT而言,我們必須在源代碼中手工匯編所有的菜單。<br>
<br>
628-630頁程序<br>
<br>
在這個(gè)程序中,我避免了為每個(gè)菜單編寫典型的冗長(zhǎng)的add()列表調(diào)用,因?yàn)槟强雌饋硐裨S多的無用的標(biāo)志。取而代之的是,我安放菜單項(xiàng)到數(shù)組中,然后在一個(gè)for的循環(huán)中通過每個(gè)數(shù)組調(diào)用add()簡(jiǎn)單地跳過。這樣的話,增加和減少菜單項(xiàng)變得沒那么討厭了。<br>
作為一個(gè)可選擇的方法(我發(fā)現(xiàn)這很難令我滿意,因?yàn)樗枰嗟姆峙洌〤heckboxMenuItems在數(shù)組的句柄中被創(chuàng)建是被稱為安全創(chuàng)建;這對(duì)數(shù)組文件和其它的文件而言是真正的安全。<br>
程序中創(chuàng)建了不是一個(gè)而是二個(gè)的菜單條來證明菜單條在程序運(yùn)行時(shí)能被交換激活。我們可以看到菜單條怎樣組成菜單,每個(gè)菜單怎樣組成菜單項(xiàng)(MenuItems),chenkboxMenuItems或者其它的菜單(產(chǎn)生子菜單)。當(dāng)菜單組合后,可以用setMenuBar()方法安裝到現(xiàn)在的程序中。值得注意的是當(dāng)按鈕被壓下時(shí),它將檢查當(dāng)前的菜單安裝使用getMenuBar(),然后安放其它的菜單條在它的位置上。<br>
當(dāng)測(cè)試是“open”(即開始)時(shí),注意拼寫和大寫,如果開始時(shí)沒有對(duì)象,Java發(fā)出no
error(沒有錯(cuò)誤)的信號(hào)。這種字符串比較是一個(gè)明顯的程序設(shè)計(jì)錯(cuò)誤源。<br>
校驗(yàn)和非校驗(yàn)的菜單項(xiàng)自動(dòng)地運(yùn)行,與之相關(guān)的CheckBoxMenuItems著實(shí)令人吃驚,這是因?yàn)橐恍┰蛩鼈儾辉试S字符串匹配。(這似乎是自相矛盾的,盡管字符串匹配并不是一種很好的辦法。)因此,我們可以匹配一個(gè)目標(biāo)對(duì)象而不是它們的標(biāo)簽。當(dāng)演示時(shí),getState()方法用來顯示狀態(tài)。我們同樣可以用setState()改變CheckboxMenuItem的狀態(tài)。<br>
我們可能會(huì)認(rèn)為一個(gè)菜單可以合理地置入超過一個(gè)的菜單條中。這看似合理,因?yàn)樗形覀兒雎缘牟藛螚l的add()方法都是一個(gè)句柄。然而,如果我們?cè)噲D這樣做,這個(gè)結(jié)果將會(huì)變得非常的別扭,而遠(yuǎn)非我們所希望得到的結(jié)果。(很難知道這是一個(gè)編程中的錯(cuò)誤或者說是他們?cè)噲D使它以這種方法去運(yùn)行所產(chǎn)生的。)這個(gè)例子同樣向我們展示了為什么我們需要建立一個(gè)應(yīng)用程序以替代程序片。(這是因?yàn)閼?yīng)用程序能支持菜單,而程序片是不能直接使用菜單的。)我們從幀處繼承代替從程序片處繼承。另外,我們?yōu)轭惤ㄒ粋€(gè)構(gòu)建器以取代init()安裝事件。最后,我們創(chuàng)建一個(gè)main()方法并且在我們建的新型對(duì)象里,調(diào)整它的大小,然后調(diào)用show()。它與程序片只在很小的地方有不同之處,然而這時(shí)它已經(jīng)是一個(gè)獨(dú)立的設(shè)置窗口應(yīng)用程序并且我們可以使用菜單。<br>
<br>
13.15.2 對(duì)話框<br>
對(duì)話框是一個(gè)從其它窗口彈出的窗口。它的目的是處理一些特殊的爭(zhēng)議和它們的細(xì)節(jié)而不使原來的窗口陷入混亂之中。對(duì)話框大量在設(shè)置窗口的編程環(huán)境中使用,但就像前面提到的一樣,鮮于在程序片中使用。<br>
我們需要從對(duì)話類處繼承以創(chuàng)建其它類型的窗口、像幀一樣的對(duì)話框。和窗框不同,對(duì)話框不能擁有菜單條也不能改變光標(biāo),但除此之外它們十分的相似。一個(gè)對(duì)話框擁有布局管理器(默認(rèn)的是BorderLayout布局管理器)和過載action()等等,或用handleEvent()去處理事件。我們會(huì)注意到handleEvent()的一個(gè)重要差異:當(dāng)WINDOW_DESTORY事件發(fā)生時(shí),我們并不希望關(guān)閉正在運(yùn)行的應(yīng)用程序!<br>
相反,我們可以使用對(duì)話窗口通過調(diào)用dispace()釋放資源。在下面的例子中,對(duì)話框是由定義在那兒作為類的ToeButton的特殊按鈕組成的網(wǎng)格構(gòu)成的(利用GridLayout布局管理器)。ToeButton按鈕圍繞它自已畫了一個(gè)幀,并且依賴它的狀態(tài):在空的中的“X”或者“O”。它從空白開始,然后依靠使用者的選擇,轉(zhuǎn)換成“X”或“O”。但是,當(dāng)我們單擊在按鈕上時(shí),它會(huì)在“X”和“O”之間來回交換。(這產(chǎn)生了一種類似填字游戲的感覺,當(dāng)然比它更令人討厭。)另外,這個(gè)對(duì)話框可以被設(shè)置為在主應(yīng)用程序窗口中為很多的行和列變更號(hào)碼。<br>
<br>
632-634頁程序<br>
<br>
ToeButton類保留了一個(gè)句柄到它ToeDialog型的父類中。正如前面所述,ToeButton和ToeDialog高度的結(jié)合因?yàn)橐粋€(gè)ToeButton只能被一個(gè)ToeDialog所使用,但它卻解決了一系列的問題,事實(shí)上這實(shí)在不是一個(gè)糟糕的解決方案因?yàn)闆]有另外的可以記錄用戶選擇的對(duì)話類。當(dāng)然我們可以使用其它的制造ToeDialog.turn(ToeButton的靜態(tài)的一部分)方法。這種方法消除了它們的緊密聯(lián)系,但卻阻止了我們一次擁有多個(gè)ToeDialog(無論如何,至少有一個(gè)正常地運(yùn)行)。<br>
paint()是一種與圖形有關(guān)的方法:它圍繞按鈕畫出矩形并畫出“X”或“O”。這完全是冗長(zhǎng)的計(jì)算,但卻十分的直觀。<br>
一個(gè)鼠標(biāo)單擊被過載的mouseDown()方法所俘獲,最要緊的是檢查是否有事件寫在按鈕上。如果沒有,父窗口會(huì)被詢問以找出誰選擇了它并用來確定按鈕的狀態(tài)。值得注意的是按鈕隨后交回到父類中并且改變它的選擇。如果按鈕已經(jīng)顯示這為“X”和“O”,那么它們會(huì)被改變狀態(tài)。我們能注意到本書第三章中描述的在這些計(jì)算中方便的使用的三個(gè)一組的If-else。當(dāng)一個(gè)按鈕的狀態(tài)改變后,按鈕會(huì)被重畫。<br>
ToeDialog的構(gòu)建器十分的簡(jiǎn)單:它像我們所需要的一樣增加一些按鈕到GridLayout布局管理器中,然后調(diào)整每個(gè)按鈕每邊大小為50個(gè)像素(如果我們不調(diào)整窗口,那么它就不會(huì)顯示出來)。注意handleEvent()正好為WINDOW_DESTROY調(diào)用dispose(),因此整個(gè)應(yīng)用程序不會(huì)被關(guān)閉。<br>
ToeTest設(shè)置整個(gè)應(yīng)用程序以創(chuàng)建TextField(為輸入按鈕網(wǎng)格的行和列)和“go”按鈕。我們會(huì)領(lǐng)會(huì)action()在這個(gè)程序中使用不太令人滿意的“字符串匹配”技術(shù)來測(cè)試按鈕的按下(請(qǐng)確定我們拼寫和大寫都是正確的!)。當(dāng)按鈕按下時(shí),TextField中的數(shù)據(jù)將被取出,并且,因?yàn)樗鼈冊(cè)谧址Y(jié)構(gòu)中,所以需要利用靜態(tài)的Integer.paresInt()方法來轉(zhuǎn)變成中斷。一旦對(duì)話類被建立,我們就必須調(diào)用show()方法來顯示和激活它。<br>
我們會(huì)注意到ToeDialo
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -