'java基礎技術提升篇:java AWT'

Java 編程語言 技術 設計 95後碼農 2019-07-23
"

AWT

"

AWT

java基礎技術提升篇:java AWT

在Java 1.1中一個顯著的改變就是完善了新AWT的創新。大多數的改變圍繞在Java 1.1中使用的新事件模型:老的事件模型是糟糕的、笨拙的、非面向對象的,而新的事件模型可能是我所見過的最優秀的。難以理解一個如此糟糕的(老的AWT)和一個如此優秀的(新的事件模型)程序語言居然出自同一個集團之手。新的考慮事件的方法看來中止了,因此爭議不再變成障礙,從而輕易進入我們的意識裡;相反,它是一個幫助我們設計系統的工具。它同樣是Java Beans的精華,我們會在本章後面部分進入講述。

新的方法設計對象做為“事件源”和“事件接收器”以代替老AWT的非面向對象串聯的條件語句。正象我們將看到的內部類的用途是集成面向對象的原始狀態的新事件。另外,事件現在被描繪為在一個類體系以取代單一的類並且我們可以創建自己的事件類型。

新的事件模型

在新的事件模型的組件可以開始一個事件。每種類型的事件被一個個別的類所描繪。當事件開始後,它受理一個或更多事件指明“接收器”。因此,事件源和處理事件的地址可以被分離。

每個“接收器”都是執行特定的接收器類型接口的類對象。因此作為一個程序開發者,我們所要做的是創建“接收器對象”並且在被激活事件的組件中進行註冊。event-firing組件調用一個addXXXListener()方法來完成註冊,以描述XXX事件類型接受。我們可以容易地瞭解到以addListened名的方法通知我們任何的事件類型都可以被處理,如果我們試圖接收事件我們會發現編譯時我們的錯誤。Java Beans同樣使用這種addListener名的方法去判斷那一個程序可以運行。

我們所有的事件邏輯將裝入到一個接收器類中。當我們創建一個接收器類時唯一的一點限制是必須執行專用的接口。我們可以創建一個全局接收器類,這種情況在內部類中有助於被很好地使用,不僅僅是因為它們提供了一個理論上的接收器類組到它們服務的UI或業務邏輯類中,但因為事實是一個內部類維持一個句柄到它的父對象,提供了一個很好的通過類和子系統邊界的調用方法。

一個簡單的例子將使這一切變得清晰明確。同時思考本章前部Button2.java例子與這個例子的差異。

//: Button2New.java
// Capturing button presses
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2New extends Applet {
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
public void init() {
b1.addActionListener(new B1());            //b1為事件源  new B1為接收器對象
b2.addActionListener(new B2());             //addXXXListener註冊到“事件組件”
add(b1);
add(b2);
}
class B1 implements ActionListener {             //接收器類
public void actionPerformed(ActionEvent e) {
getAppletContext().showStatus("Button 1");
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
getAppletContext().showStatus("Button 2");
}
}
/* 老的AWT方式:
public boolean action(Event evt, Object arg) {
if(evt.target.equals(b1))                    //所有的事件源被統一集中處理  
getAppletContext().showStatus("Button 1");
else if(evt.target.equals(b2))                  //發生了什麼
getAppletContext().showStatus("Button 2");          //怎樣處理
// Let the base class handle it:
else
return super.action(evt, arg);
return true; // We've handled it here
}
*/
} ///:~

我們可比較兩種方法,老的代碼在左面作為註解。在init()方法裡,只有一個改變就是增加了下面的兩行:

b1.addActionListener(new B1());

b2.addActionListener(new B2());

按鈕按下時,addActionListener()通知按鈕對象被激活。B1和B2類都是執行接口ActionListener的內部類。這個接口包括一個單一的方法actionPerformed()(這意味著當事件激活時,這個動作將被執行)。注意actionPreformed()方法不是一個普通事件,說得更恰當些是一個特殊類型的事件,ActionEvent。如果我們想提取特殊ActionEvent的信息,因此我們不需要故意去測試和下溯造型自變量。

對編程者來說重寫事件actionPerformed()十分的簡單。它是一個可以調用的方法。同老的action()方法比較,老的方法我們必須指出發生了什麼和適當的動作,同樣,我們會擔心調用基礎類action()的版本並且返回一個值去指明是否被處理。在新的事件模型中,我們知道所有事件測試推理自動進行,因此我們不必指出發生了什麼;我們剛剛表示發生了什麼,它就自動地完成了。如果我們還沒有提出用新的方法覆蓋老的方法,我們會很快提出。

在這裡介紹一下程序片、視窗應用。

程序片:

程序片的侷限,出於安全緣故,程序片十分受到限制,並且有很多的事我們都不能做。您一般會問:程序片看起來能做什麼,傳聞它又能做什麼:擴展瀏覽器中WEB頁的功能。自從作為一個網上衝浪者,我們從未真正想了解是否一個WEB頁來自友好的或者不友好的站點,我們想要一些可以安全地行動的代碼。所以我們可能會注意到大量的限制:

(1) 一個程序片不能接觸到本地的磁盤。這意味著不能在本地磁盤上寫和讀,我們不想一個程序片通過WEB頁面閱讀和傳送重要的信息。寫是被禁止的,當然,因為那將會引起病毒的侵入。當數字簽名生效時,這些限制會被解除。

(2) 程序片不能擁有菜單。(注意:這是規定在Swing中的)這可能會減少關於安全和關於程序簡化的麻煩。我們可能會接到有關程序片協調利益以作為WEB頁面的一部分的通知;而我們通常不去注意程序片的範圍。這兒沒有幀和標題條從菜單處彈出,出現的幀和標題條是屬於WEB瀏覽器的。也許將來設計能被改變成允許我們將瀏覽器菜單和程序片菜單相結合起來——程序片可以影響它的環境將導致太危及整個系統的安全並使程序片過於的複雜。

(3) 對話框是不被信任的。在Java中,對話框存在一些令人難解的地方。首先,它們不能正確地拒絕程序片,這實在是令人沮喪。如果我們從程序片彈出一個對話框,我們會在對話框上看到一個附上的消息框“不被信任的程序片”。這是因為在理論上,它有可能欺騙用戶去考慮他們在通過WEB同一個老顧客的本地應用程序交易並且讓他們輸入他們的信用卡號。在看到AWT開發的那種GUI後,我們可能會難過地相信任何人都會被那種方法所愚弄。但程序片是一直附著在一個Web頁面上的,並可以在瀏覽器中看到,而對話框沒有這種依附關係,所以理論上是可能的。因此,我們很少會見到一個使用對話框的程序片。

在較新的瀏覽器中,對受到信任的程序片來說,許多限制都被放寬了(受信任程序片由一個信任源認證)。

涉及程序片的開發時,還有另一些問題需要考慮:

■程序片不停地從一個適合不同類的單獨的服務器上下載。我們的瀏覽器能夠緩存程序片,但這沒有保證。在Java 1.1版中的一個改進是JAR(Java ARchive)文件,它允許將所有的程序片組件(包括其它的類文件、圖像、聲音)一起打包到一個的能被單個服務器處理下載的壓縮文件。“數字簽字”(能校驗類創建器)可有效地加入每個單獨的JAR文件。

■因為安全方面的緣故,我們做某些工作更加困難,例如訪問數據庫和發送電子郵件。另外,安全限制規則使訪問多個主機變得非常的困難,因為每一件事都必須通過WEB服務器路由,形成一個性能瓶頸,並且單一環節的出錯都會導致整個處理的停止。

■瀏覽器裡的程序片不會擁有同樣的本地應用程序運行的控件類型。例如,自從用戶可以開關頁面以來,在程序片中不會擁有一個形式上的對話框。當用戶對一個WEB頁面進行改變或退出瀏覽器時,對我們的程序片而言簡直是一場災難——這時沒有辦法保存狀態,所以如果我們在處理和操作中時,信息會被丟失。另外,當我們離開一個WEB頁面時,不同的瀏覽器會對我們的程序片做不同的操作,因此結果本來就是不確定的。

程序片的優點

如果能容忍那些限制,那麼程序片的一些優點也是非常突出的,尤其是在我們構建客戶/服務器應用或者其它網絡應用時:

■沒有安裝方面的爭議。程序片擁有真正的平臺獨立性(包括容易地播放聲音文件等能力)所以我們不需要針對不同的平臺修改代碼也不需要任何人根據安裝運行任何的“tweaking”。事實上,安裝每次自動地將WEB頁連同程序片一起,因此安靜、自動地更新。在傳統的客戶機/服務器系統中,建立和安裝一個新版本的客戶端軟件簡直就是一場惡夢。

■因為安全的原因創建在核心Java語言和程序片結構中,我們不必擔心壞的代碼而導致毀壞某人的系統。這樣,連同前面的優點,可使用Java(可從JavaScript和VBScript中選擇客戶端的WEB編程工具)為所謂的Intrant(在公司內部使用而不向Internet轉移的企業內部網絡)客戶機/服務器開發應用程序。

■由於程序片是自動同HTML集成的,所以我們有一個內建的獨立平臺文件系統去支持程序片。這是一個很有趣的方法,因為我們慣於擁有程序文件的一部分而不是相反的擁有文件系統。

視窗化應用

出於安全的緣故,我們會看到在程序片我們的行為非常的受到限制。我們真實地感到,程序片是被臨時地加入在WEB瀏覽器中的,因此,它的功能連同它的相關知識,控件都必須加以限制。但是,我們希望Java能製造一個開窗口的程序去運行一些事物,否則寧願安放在一個WEB頁面上,並且也許我們希望它可以運行一些可靠的應用程序,以及誇張的實時便攜性。在這本書前面的章節中我們製造了一些命令行應用程序,但在一些操作環境中(例如:Macintosh)沒有命令行。所以我們有很多的理由去利用Java創建一個設置窗口,非程序片的程序。這當然是一個十分合理的要求。

一個Java設置窗口應用程序可以擁有菜單和對話框(這對一個程序片來說是不可能的和很困難的),可是如果我們使用一個老版本的Java,我們將會犧牲本地操作系統環境的外觀和感受。JFC/Swing庫允許我們製造一個保持原來操作系統環境的外觀和感受的應用程序。如果我們想建立一個設置窗口應用程序,它會合理地運作,同樣,如果我們可以使用最新版本的Java並且集合所有的工具,我們就可以發佈不會使用戶困惑的應用程序。如果因為一些原因,我們被迫使用老版本的Java,請在毀壞以建立重要的設置窗口的應用程序前仔細地考慮。

用Java 1.1 AWT製作窗口和程序片

我們經常都需要創建一個類,使其既可作為一個窗口調用,亦可作為一個程序片調用。為做到這一點,只需為程序片簡單地加入一個main()即可,令其在一個Frame(幀)裡構建程序片的一個實例。作為一個簡單的示例,下面讓我們來看看如何對Button2New.java作一番修改,使其能同時作為應用程序和程序片使用:

//: Button2NewB.java
// An application and an applet
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2NewB extends Applet {    //程序片
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
TextField t = new TextField(20);
public void init() {
b1.addActionListener(new B1());
b2.addActionListener(new B2());
add(b1);
add(b2);
add(t);
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Button 1");
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Button 2");
}
}
// To close the application:
static class WL extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
// A main() for the application:
public static void main(String[] args) {        //視窗應用
Button2NewB applet = new Button2NewB();
Frame aFrame = new Frame("Button2NewB");
aFrame.addWindowListener(new WL());
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~

內部類WL和main()方法是加入程序片的唯一兩個元素,程序片剩餘的部分則原封未動。事實上,我們通常將WL類和main()方法做一結小的改進複製和粘貼到我們自己的程序片裡(請記住創建內部類時通常需要一個外部類來處理它,形成它靜態地消除這個需要)。我們可以看到在main()方法裡,程序片明確地初始化和開始,因為在這個例子裡瀏覽器不能為我們有效地運行它。當然,這不會提供全部的瀏覽器調用stop()和destroy()的行為,但對大多數的情況而言它都是可接受的。如果它變成一個麻煩,我們可以:

(1) 使程序片句柄為一個靜態類(以代替局部可變的main()),然後:

(2) 在我們調用System.exit()之前在WindowAdapter.windowClosing()中調用applet.stop()和applet.destroy()。

注意最後一行:

aFrame.setVisible(true);

這是Java 1.1 AWT的一個改變。show()方法不再被支持,而setVisible(true)則取代了show()方法。當我們在本章後面部分學習Java Beans時,這些表面上易於改變的方法將會變得更加的合理。

這個例子同樣被使用TextField修改而不是顯示到控制檯或瀏覽器狀態行上。在開發程序時有一個限制條件就是程序片和應用程序我們都必須根據它們的運行情況選擇輸入和輸出結構。

這裡展示了Java 1.1 AWT的其它小的新功能。我們不再需要去使用有錯誤傾向的利用字符串指定BorderLayout定位的方法。當我們增加一個元素到Java 1.1版的BorderLayout中時,我們可以這樣寫:

aFrame.add(applet, BorderLayout.CENTER);

我們對位置規定一個BorderLayout的常數,以使它能在編譯時被檢驗(而不是對老的結構悄悄地做不合適的事)。這是一個顯著的改善,並且將在這本書的餘下部分大量地使用。

將窗口接收器變成匿名類

任何一個接收器類都可作為一個匿名類執行,但這一直有個意外,那就是我們可能需要在其它場合使用它們的功能。但是,窗口接收器在這裡僅作為關閉應用程序窗口來使用,因此我們可以安全地製造一個匿名類。然後,main()中的下面這行代碼:

aFrame.addWindowListener(new WL());

會變成:

aFrame.addWindowListener(new WindowAdapter() { //創建匿名類接收器對象,aFrame為事件源
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

這有一個優點就是它不需要其它的類名。我們必須對自己判斷是否它使代碼變得易於理解或者更難。不過,對本書餘下部分而言,匿名內部類將通常被使用在窗口接收器中。

將程序片封裝到JAR文件裡

一個重要的JAR應用就是完善程序片的裝載。在Java 1.0版中,人們傾向於試法將它們的代碼填入到單個的程序片類裡,因此客戶只需要單個的服務器就可適合下載程序片代碼。但這不僅使結果凌亂,難以閱讀(當然維護也然)程序,但類文件一直不能壓縮,因此下載從來沒有快過。

JAR文件將我們所有的被壓縮的類文件打包到一個單個兒的文件中,再被瀏覽器下載。現在我們不需要創建一個糟糕的設計以最小化我們創建的類,並且用戶將得到更快地下載速度。

仔細想想上面的例子,這個例子看起來像Button2NewB,是一個單類,但事實上它包含三個內部類,因此共有四個。每當我們編譯程序,我會用這行代碼打包它到一個JAR文件:

jar cf Button2NewB.jar *.class

這是假定只有一個類文件在當前目錄中,其中之一來自Button2NewB.java(否則我們會得到特別的打包)。

現在我們可以創建一個使用新文件標籤來指定JAR文件的HTML頁,如下所示:

<head><title>Button2NewB Example Applet</title></head>
<body>
  <applet code="Button2NewB.class"
  archive="Button2NewB.jar"
  width=200 height=150>
  </applet>
</body>

與HTML文件中的程序片標記有關的其他任何內容都保持不變。

"

AWT

java基礎技術提升篇:java AWT

在Java 1.1中一個顯著的改變就是完善了新AWT的創新。大多數的改變圍繞在Java 1.1中使用的新事件模型:老的事件模型是糟糕的、笨拙的、非面向對象的,而新的事件模型可能是我所見過的最優秀的。難以理解一個如此糟糕的(老的AWT)和一個如此優秀的(新的事件模型)程序語言居然出自同一個集團之手。新的考慮事件的方法看來中止了,因此爭議不再變成障礙,從而輕易進入我們的意識裡;相反,它是一個幫助我們設計系統的工具。它同樣是Java Beans的精華,我們會在本章後面部分進入講述。

新的方法設計對象做為“事件源”和“事件接收器”以代替老AWT的非面向對象串聯的條件語句。正象我們將看到的內部類的用途是集成面向對象的原始狀態的新事件。另外,事件現在被描繪為在一個類體系以取代單一的類並且我們可以創建自己的事件類型。

新的事件模型

在新的事件模型的組件可以開始一個事件。每種類型的事件被一個個別的類所描繪。當事件開始後,它受理一個或更多事件指明“接收器”。因此,事件源和處理事件的地址可以被分離。

每個“接收器”都是執行特定的接收器類型接口的類對象。因此作為一個程序開發者,我們所要做的是創建“接收器對象”並且在被激活事件的組件中進行註冊。event-firing組件調用一個addXXXListener()方法來完成註冊,以描述XXX事件類型接受。我們可以容易地瞭解到以addListened名的方法通知我們任何的事件類型都可以被處理,如果我們試圖接收事件我們會發現編譯時我們的錯誤。Java Beans同樣使用這種addListener名的方法去判斷那一個程序可以運行。

我們所有的事件邏輯將裝入到一個接收器類中。當我們創建一個接收器類時唯一的一點限制是必須執行專用的接口。我們可以創建一個全局接收器類,這種情況在內部類中有助於被很好地使用,不僅僅是因為它們提供了一個理論上的接收器類組到它們服務的UI或業務邏輯類中,但因為事實是一個內部類維持一個句柄到它的父對象,提供了一個很好的通過類和子系統邊界的調用方法。

一個簡單的例子將使這一切變得清晰明確。同時思考本章前部Button2.java例子與這個例子的差異。

//: Button2New.java
// Capturing button presses
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2New extends Applet {
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
public void init() {
b1.addActionListener(new B1());            //b1為事件源  new B1為接收器對象
b2.addActionListener(new B2());             //addXXXListener註冊到“事件組件”
add(b1);
add(b2);
}
class B1 implements ActionListener {             //接收器類
public void actionPerformed(ActionEvent e) {
getAppletContext().showStatus("Button 1");
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
getAppletContext().showStatus("Button 2");
}
}
/* 老的AWT方式:
public boolean action(Event evt, Object arg) {
if(evt.target.equals(b1))                    //所有的事件源被統一集中處理  
getAppletContext().showStatus("Button 1");
else if(evt.target.equals(b2))                  //發生了什麼
getAppletContext().showStatus("Button 2");          //怎樣處理
// Let the base class handle it:
else
return super.action(evt, arg);
return true; // We've handled it here
}
*/
} ///:~

我們可比較兩種方法,老的代碼在左面作為註解。在init()方法裡,只有一個改變就是增加了下面的兩行:

b1.addActionListener(new B1());

b2.addActionListener(new B2());

按鈕按下時,addActionListener()通知按鈕對象被激活。B1和B2類都是執行接口ActionListener的內部類。這個接口包括一個單一的方法actionPerformed()(這意味著當事件激活時,這個動作將被執行)。注意actionPreformed()方法不是一個普通事件,說得更恰當些是一個特殊類型的事件,ActionEvent。如果我們想提取特殊ActionEvent的信息,因此我們不需要故意去測試和下溯造型自變量。

對編程者來說重寫事件actionPerformed()十分的簡單。它是一個可以調用的方法。同老的action()方法比較,老的方法我們必須指出發生了什麼和適當的動作,同樣,我們會擔心調用基礎類action()的版本並且返回一個值去指明是否被處理。在新的事件模型中,我們知道所有事件測試推理自動進行,因此我們不必指出發生了什麼;我們剛剛表示發生了什麼,它就自動地完成了。如果我們還沒有提出用新的方法覆蓋老的方法,我們會很快提出。

在這裡介紹一下程序片、視窗應用。

程序片:

程序片的侷限,出於安全緣故,程序片十分受到限制,並且有很多的事我們都不能做。您一般會問:程序片看起來能做什麼,傳聞它又能做什麼:擴展瀏覽器中WEB頁的功能。自從作為一個網上衝浪者,我們從未真正想了解是否一個WEB頁來自友好的或者不友好的站點,我們想要一些可以安全地行動的代碼。所以我們可能會注意到大量的限制:

(1) 一個程序片不能接觸到本地的磁盤。這意味著不能在本地磁盤上寫和讀,我們不想一個程序片通過WEB頁面閱讀和傳送重要的信息。寫是被禁止的,當然,因為那將會引起病毒的侵入。當數字簽名生效時,這些限制會被解除。

(2) 程序片不能擁有菜單。(注意:這是規定在Swing中的)這可能會減少關於安全和關於程序簡化的麻煩。我們可能會接到有關程序片協調利益以作為WEB頁面的一部分的通知;而我們通常不去注意程序片的範圍。這兒沒有幀和標題條從菜單處彈出,出現的幀和標題條是屬於WEB瀏覽器的。也許將來設計能被改變成允許我們將瀏覽器菜單和程序片菜單相結合起來——程序片可以影響它的環境將導致太危及整個系統的安全並使程序片過於的複雜。

(3) 對話框是不被信任的。在Java中,對話框存在一些令人難解的地方。首先,它們不能正確地拒絕程序片,這實在是令人沮喪。如果我們從程序片彈出一個對話框,我們會在對話框上看到一個附上的消息框“不被信任的程序片”。這是因為在理論上,它有可能欺騙用戶去考慮他們在通過WEB同一個老顧客的本地應用程序交易並且讓他們輸入他們的信用卡號。在看到AWT開發的那種GUI後,我們可能會難過地相信任何人都會被那種方法所愚弄。但程序片是一直附著在一個Web頁面上的,並可以在瀏覽器中看到,而對話框沒有這種依附關係,所以理論上是可能的。因此,我們很少會見到一個使用對話框的程序片。

在較新的瀏覽器中,對受到信任的程序片來說,許多限制都被放寬了(受信任程序片由一個信任源認證)。

涉及程序片的開發時,還有另一些問題需要考慮:

■程序片不停地從一個適合不同類的單獨的服務器上下載。我們的瀏覽器能夠緩存程序片,但這沒有保證。在Java 1.1版中的一個改進是JAR(Java ARchive)文件,它允許將所有的程序片組件(包括其它的類文件、圖像、聲音)一起打包到一個的能被單個服務器處理下載的壓縮文件。“數字簽字”(能校驗類創建器)可有效地加入每個單獨的JAR文件。

■因為安全方面的緣故,我們做某些工作更加困難,例如訪問數據庫和發送電子郵件。另外,安全限制規則使訪問多個主機變得非常的困難,因為每一件事都必須通過WEB服務器路由,形成一個性能瓶頸,並且單一環節的出錯都會導致整個處理的停止。

■瀏覽器裡的程序片不會擁有同樣的本地應用程序運行的控件類型。例如,自從用戶可以開關頁面以來,在程序片中不會擁有一個形式上的對話框。當用戶對一個WEB頁面進行改變或退出瀏覽器時,對我們的程序片而言簡直是一場災難——這時沒有辦法保存狀態,所以如果我們在處理和操作中時,信息會被丟失。另外,當我們離開一個WEB頁面時,不同的瀏覽器會對我們的程序片做不同的操作,因此結果本來就是不確定的。

程序片的優點

如果能容忍那些限制,那麼程序片的一些優點也是非常突出的,尤其是在我們構建客戶/服務器應用或者其它網絡應用時:

■沒有安裝方面的爭議。程序片擁有真正的平臺獨立性(包括容易地播放聲音文件等能力)所以我們不需要針對不同的平臺修改代碼也不需要任何人根據安裝運行任何的“tweaking”。事實上,安裝每次自動地將WEB頁連同程序片一起,因此安靜、自動地更新。在傳統的客戶機/服務器系統中,建立和安裝一個新版本的客戶端軟件簡直就是一場惡夢。

■因為安全的原因創建在核心Java語言和程序片結構中,我們不必擔心壞的代碼而導致毀壞某人的系統。這樣,連同前面的優點,可使用Java(可從JavaScript和VBScript中選擇客戶端的WEB編程工具)為所謂的Intrant(在公司內部使用而不向Internet轉移的企業內部網絡)客戶機/服務器開發應用程序。

■由於程序片是自動同HTML集成的,所以我們有一個內建的獨立平臺文件系統去支持程序片。這是一個很有趣的方法,因為我們慣於擁有程序文件的一部分而不是相反的擁有文件系統。

視窗化應用

出於安全的緣故,我們會看到在程序片我們的行為非常的受到限制。我們真實地感到,程序片是被臨時地加入在WEB瀏覽器中的,因此,它的功能連同它的相關知識,控件都必須加以限制。但是,我們希望Java能製造一個開窗口的程序去運行一些事物,否則寧願安放在一個WEB頁面上,並且也許我們希望它可以運行一些可靠的應用程序,以及誇張的實時便攜性。在這本書前面的章節中我們製造了一些命令行應用程序,但在一些操作環境中(例如:Macintosh)沒有命令行。所以我們有很多的理由去利用Java創建一個設置窗口,非程序片的程序。這當然是一個十分合理的要求。

一個Java設置窗口應用程序可以擁有菜單和對話框(這對一個程序片來說是不可能的和很困難的),可是如果我們使用一個老版本的Java,我們將會犧牲本地操作系統環境的外觀和感受。JFC/Swing庫允許我們製造一個保持原來操作系統環境的外觀和感受的應用程序。如果我們想建立一個設置窗口應用程序,它會合理地運作,同樣,如果我們可以使用最新版本的Java並且集合所有的工具,我們就可以發佈不會使用戶困惑的應用程序。如果因為一些原因,我們被迫使用老版本的Java,請在毀壞以建立重要的設置窗口的應用程序前仔細地考慮。

用Java 1.1 AWT製作窗口和程序片

我們經常都需要創建一個類,使其既可作為一個窗口調用,亦可作為一個程序片調用。為做到這一點,只需為程序片簡單地加入一個main()即可,令其在一個Frame(幀)裡構建程序片的一個實例。作為一個簡單的示例,下面讓我們來看看如何對Button2New.java作一番修改,使其能同時作為應用程序和程序片使用:

//: Button2NewB.java
// An application and an applet
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2NewB extends Applet {    //程序片
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
TextField t = new TextField(20);
public void init() {
b1.addActionListener(new B1());
b2.addActionListener(new B2());
add(b1);
add(b2);
add(t);
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Button 1");
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Button 2");
}
}
// To close the application:
static class WL extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
// A main() for the application:
public static void main(String[] args) {        //視窗應用
Button2NewB applet = new Button2NewB();
Frame aFrame = new Frame("Button2NewB");
aFrame.addWindowListener(new WL());
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~

內部類WL和main()方法是加入程序片的唯一兩個元素,程序片剩餘的部分則原封未動。事實上,我們通常將WL類和main()方法做一結小的改進複製和粘貼到我們自己的程序片裡(請記住創建內部類時通常需要一個外部類來處理它,形成它靜態地消除這個需要)。我們可以看到在main()方法裡,程序片明確地初始化和開始,因為在這個例子裡瀏覽器不能為我們有效地運行它。當然,這不會提供全部的瀏覽器調用stop()和destroy()的行為,但對大多數的情況而言它都是可接受的。如果它變成一個麻煩,我們可以:

(1) 使程序片句柄為一個靜態類(以代替局部可變的main()),然後:

(2) 在我們調用System.exit()之前在WindowAdapter.windowClosing()中調用applet.stop()和applet.destroy()。

注意最後一行:

aFrame.setVisible(true);

這是Java 1.1 AWT的一個改變。show()方法不再被支持,而setVisible(true)則取代了show()方法。當我們在本章後面部分學習Java Beans時,這些表面上易於改變的方法將會變得更加的合理。

這個例子同樣被使用TextField修改而不是顯示到控制檯或瀏覽器狀態行上。在開發程序時有一個限制條件就是程序片和應用程序我們都必須根據它們的運行情況選擇輸入和輸出結構。

這裡展示了Java 1.1 AWT的其它小的新功能。我們不再需要去使用有錯誤傾向的利用字符串指定BorderLayout定位的方法。當我們增加一個元素到Java 1.1版的BorderLayout中時,我們可以這樣寫:

aFrame.add(applet, BorderLayout.CENTER);

我們對位置規定一個BorderLayout的常數,以使它能在編譯時被檢驗(而不是對老的結構悄悄地做不合適的事)。這是一個顯著的改善,並且將在這本書的餘下部分大量地使用。

將窗口接收器變成匿名類

任何一個接收器類都可作為一個匿名類執行,但這一直有個意外,那就是我們可能需要在其它場合使用它們的功能。但是,窗口接收器在這裡僅作為關閉應用程序窗口來使用,因此我們可以安全地製造一個匿名類。然後,main()中的下面這行代碼:

aFrame.addWindowListener(new WL());

會變成:

aFrame.addWindowListener(new WindowAdapter() { //創建匿名類接收器對象,aFrame為事件源
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

這有一個優點就是它不需要其它的類名。我們必須對自己判斷是否它使代碼變得易於理解或者更難。不過,對本書餘下部分而言,匿名內部類將通常被使用在窗口接收器中。

將程序片封裝到JAR文件裡

一個重要的JAR應用就是完善程序片的裝載。在Java 1.0版中,人們傾向於試法將它們的代碼填入到單個的程序片類裡,因此客戶只需要單個的服務器就可適合下載程序片代碼。但這不僅使結果凌亂,難以閱讀(當然維護也然)程序,但類文件一直不能壓縮,因此下載從來沒有快過。

JAR文件將我們所有的被壓縮的類文件打包到一個單個兒的文件中,再被瀏覽器下載。現在我們不需要創建一個糟糕的設計以最小化我們創建的類,並且用戶將得到更快地下載速度。

仔細想想上面的例子,這個例子看起來像Button2NewB,是一個單類,但事實上它包含三個內部類,因此共有四個。每當我們編譯程序,我會用這行代碼打包它到一個JAR文件:

jar cf Button2NewB.jar *.class

這是假定只有一個類文件在當前目錄中,其中之一來自Button2NewB.java(否則我們會得到特別的打包)。

現在我們可以創建一個使用新文件標籤來指定JAR文件的HTML頁,如下所示:

<head><title>Button2NewB Example Applet</title></head>
<body>
  <applet code="Button2NewB.class"
  archive="Button2NewB.jar"
  width=200 height=150>
  </applet>
</body>

與HTML文件中的程序片標記有關的其他任何內容都保持不變。

java基礎技術提升篇:java AWT

"

AWT

java基礎技術提升篇:java AWT

在Java 1.1中一個顯著的改變就是完善了新AWT的創新。大多數的改變圍繞在Java 1.1中使用的新事件模型:老的事件模型是糟糕的、笨拙的、非面向對象的,而新的事件模型可能是我所見過的最優秀的。難以理解一個如此糟糕的(老的AWT)和一個如此優秀的(新的事件模型)程序語言居然出自同一個集團之手。新的考慮事件的方法看來中止了,因此爭議不再變成障礙,從而輕易進入我們的意識裡;相反,它是一個幫助我們設計系統的工具。它同樣是Java Beans的精華,我們會在本章後面部分進入講述。

新的方法設計對象做為“事件源”和“事件接收器”以代替老AWT的非面向對象串聯的條件語句。正象我們將看到的內部類的用途是集成面向對象的原始狀態的新事件。另外,事件現在被描繪為在一個類體系以取代單一的類並且我們可以創建自己的事件類型。

新的事件模型

在新的事件模型的組件可以開始一個事件。每種類型的事件被一個個別的類所描繪。當事件開始後,它受理一個或更多事件指明“接收器”。因此,事件源和處理事件的地址可以被分離。

每個“接收器”都是執行特定的接收器類型接口的類對象。因此作為一個程序開發者,我們所要做的是創建“接收器對象”並且在被激活事件的組件中進行註冊。event-firing組件調用一個addXXXListener()方法來完成註冊,以描述XXX事件類型接受。我們可以容易地瞭解到以addListened名的方法通知我們任何的事件類型都可以被處理,如果我們試圖接收事件我們會發現編譯時我們的錯誤。Java Beans同樣使用這種addListener名的方法去判斷那一個程序可以運行。

我們所有的事件邏輯將裝入到一個接收器類中。當我們創建一個接收器類時唯一的一點限制是必須執行專用的接口。我們可以創建一個全局接收器類,這種情況在內部類中有助於被很好地使用,不僅僅是因為它們提供了一個理論上的接收器類組到它們服務的UI或業務邏輯類中,但因為事實是一個內部類維持一個句柄到它的父對象,提供了一個很好的通過類和子系統邊界的調用方法。

一個簡單的例子將使這一切變得清晰明確。同時思考本章前部Button2.java例子與這個例子的差異。

//: Button2New.java
// Capturing button presses
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2New extends Applet {
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
public void init() {
b1.addActionListener(new B1());            //b1為事件源  new B1為接收器對象
b2.addActionListener(new B2());             //addXXXListener註冊到“事件組件”
add(b1);
add(b2);
}
class B1 implements ActionListener {             //接收器類
public void actionPerformed(ActionEvent e) {
getAppletContext().showStatus("Button 1");
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
getAppletContext().showStatus("Button 2");
}
}
/* 老的AWT方式:
public boolean action(Event evt, Object arg) {
if(evt.target.equals(b1))                    //所有的事件源被統一集中處理  
getAppletContext().showStatus("Button 1");
else if(evt.target.equals(b2))                  //發生了什麼
getAppletContext().showStatus("Button 2");          //怎樣處理
// Let the base class handle it:
else
return super.action(evt, arg);
return true; // We've handled it here
}
*/
} ///:~

我們可比較兩種方法,老的代碼在左面作為註解。在init()方法裡,只有一個改變就是增加了下面的兩行:

b1.addActionListener(new B1());

b2.addActionListener(new B2());

按鈕按下時,addActionListener()通知按鈕對象被激活。B1和B2類都是執行接口ActionListener的內部類。這個接口包括一個單一的方法actionPerformed()(這意味著當事件激活時,這個動作將被執行)。注意actionPreformed()方法不是一個普通事件,說得更恰當些是一個特殊類型的事件,ActionEvent。如果我們想提取特殊ActionEvent的信息,因此我們不需要故意去測試和下溯造型自變量。

對編程者來說重寫事件actionPerformed()十分的簡單。它是一個可以調用的方法。同老的action()方法比較,老的方法我們必須指出發生了什麼和適當的動作,同樣,我們會擔心調用基礎類action()的版本並且返回一個值去指明是否被處理。在新的事件模型中,我們知道所有事件測試推理自動進行,因此我們不必指出發生了什麼;我們剛剛表示發生了什麼,它就自動地完成了。如果我們還沒有提出用新的方法覆蓋老的方法,我們會很快提出。

在這裡介紹一下程序片、視窗應用。

程序片:

程序片的侷限,出於安全緣故,程序片十分受到限制,並且有很多的事我們都不能做。您一般會問:程序片看起來能做什麼,傳聞它又能做什麼:擴展瀏覽器中WEB頁的功能。自從作為一個網上衝浪者,我們從未真正想了解是否一個WEB頁來自友好的或者不友好的站點,我們想要一些可以安全地行動的代碼。所以我們可能會注意到大量的限制:

(1) 一個程序片不能接觸到本地的磁盤。這意味著不能在本地磁盤上寫和讀,我們不想一個程序片通過WEB頁面閱讀和傳送重要的信息。寫是被禁止的,當然,因為那將會引起病毒的侵入。當數字簽名生效時,這些限制會被解除。

(2) 程序片不能擁有菜單。(注意:這是規定在Swing中的)這可能會減少關於安全和關於程序簡化的麻煩。我們可能會接到有關程序片協調利益以作為WEB頁面的一部分的通知;而我們通常不去注意程序片的範圍。這兒沒有幀和標題條從菜單處彈出,出現的幀和標題條是屬於WEB瀏覽器的。也許將來設計能被改變成允許我們將瀏覽器菜單和程序片菜單相結合起來——程序片可以影響它的環境將導致太危及整個系統的安全並使程序片過於的複雜。

(3) 對話框是不被信任的。在Java中,對話框存在一些令人難解的地方。首先,它們不能正確地拒絕程序片,這實在是令人沮喪。如果我們從程序片彈出一個對話框,我們會在對話框上看到一個附上的消息框“不被信任的程序片”。這是因為在理論上,它有可能欺騙用戶去考慮他們在通過WEB同一個老顧客的本地應用程序交易並且讓他們輸入他們的信用卡號。在看到AWT開發的那種GUI後,我們可能會難過地相信任何人都會被那種方法所愚弄。但程序片是一直附著在一個Web頁面上的,並可以在瀏覽器中看到,而對話框沒有這種依附關係,所以理論上是可能的。因此,我們很少會見到一個使用對話框的程序片。

在較新的瀏覽器中,對受到信任的程序片來說,許多限制都被放寬了(受信任程序片由一個信任源認證)。

涉及程序片的開發時,還有另一些問題需要考慮:

■程序片不停地從一個適合不同類的單獨的服務器上下載。我們的瀏覽器能夠緩存程序片,但這沒有保證。在Java 1.1版中的一個改進是JAR(Java ARchive)文件,它允許將所有的程序片組件(包括其它的類文件、圖像、聲音)一起打包到一個的能被單個服務器處理下載的壓縮文件。“數字簽字”(能校驗類創建器)可有效地加入每個單獨的JAR文件。

■因為安全方面的緣故,我們做某些工作更加困難,例如訪問數據庫和發送電子郵件。另外,安全限制規則使訪問多個主機變得非常的困難,因為每一件事都必須通過WEB服務器路由,形成一個性能瓶頸,並且單一環節的出錯都會導致整個處理的停止。

■瀏覽器裡的程序片不會擁有同樣的本地應用程序運行的控件類型。例如,自從用戶可以開關頁面以來,在程序片中不會擁有一個形式上的對話框。當用戶對一個WEB頁面進行改變或退出瀏覽器時,對我們的程序片而言簡直是一場災難——這時沒有辦法保存狀態,所以如果我們在處理和操作中時,信息會被丟失。另外,當我們離開一個WEB頁面時,不同的瀏覽器會對我們的程序片做不同的操作,因此結果本來就是不確定的。

程序片的優點

如果能容忍那些限制,那麼程序片的一些優點也是非常突出的,尤其是在我們構建客戶/服務器應用或者其它網絡應用時:

■沒有安裝方面的爭議。程序片擁有真正的平臺獨立性(包括容易地播放聲音文件等能力)所以我們不需要針對不同的平臺修改代碼也不需要任何人根據安裝運行任何的“tweaking”。事實上,安裝每次自動地將WEB頁連同程序片一起,因此安靜、自動地更新。在傳統的客戶機/服務器系統中,建立和安裝一個新版本的客戶端軟件簡直就是一場惡夢。

■因為安全的原因創建在核心Java語言和程序片結構中,我們不必擔心壞的代碼而導致毀壞某人的系統。這樣,連同前面的優點,可使用Java(可從JavaScript和VBScript中選擇客戶端的WEB編程工具)為所謂的Intrant(在公司內部使用而不向Internet轉移的企業內部網絡)客戶機/服務器開發應用程序。

■由於程序片是自動同HTML集成的,所以我們有一個內建的獨立平臺文件系統去支持程序片。這是一個很有趣的方法,因為我們慣於擁有程序文件的一部分而不是相反的擁有文件系統。

視窗化應用

出於安全的緣故,我們會看到在程序片我們的行為非常的受到限制。我們真實地感到,程序片是被臨時地加入在WEB瀏覽器中的,因此,它的功能連同它的相關知識,控件都必須加以限制。但是,我們希望Java能製造一個開窗口的程序去運行一些事物,否則寧願安放在一個WEB頁面上,並且也許我們希望它可以運行一些可靠的應用程序,以及誇張的實時便攜性。在這本書前面的章節中我們製造了一些命令行應用程序,但在一些操作環境中(例如:Macintosh)沒有命令行。所以我們有很多的理由去利用Java創建一個設置窗口,非程序片的程序。這當然是一個十分合理的要求。

一個Java設置窗口應用程序可以擁有菜單和對話框(這對一個程序片來說是不可能的和很困難的),可是如果我們使用一個老版本的Java,我們將會犧牲本地操作系統環境的外觀和感受。JFC/Swing庫允許我們製造一個保持原來操作系統環境的外觀和感受的應用程序。如果我們想建立一個設置窗口應用程序,它會合理地運作,同樣,如果我們可以使用最新版本的Java並且集合所有的工具,我們就可以發佈不會使用戶困惑的應用程序。如果因為一些原因,我們被迫使用老版本的Java,請在毀壞以建立重要的設置窗口的應用程序前仔細地考慮。

用Java 1.1 AWT製作窗口和程序片

我們經常都需要創建一個類,使其既可作為一個窗口調用,亦可作為一個程序片調用。為做到這一點,只需為程序片簡單地加入一個main()即可,令其在一個Frame(幀)裡構建程序片的一個實例。作為一個簡單的示例,下面讓我們來看看如何對Button2New.java作一番修改,使其能同時作為應用程序和程序片使用:

//: Button2NewB.java
// An application and an applet
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2NewB extends Applet {    //程序片
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
TextField t = new TextField(20);
public void init() {
b1.addActionListener(new B1());
b2.addActionListener(new B2());
add(b1);
add(b2);
add(t);
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Button 1");
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Button 2");
}
}
// To close the application:
static class WL extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
// A main() for the application:
public static void main(String[] args) {        //視窗應用
Button2NewB applet = new Button2NewB();
Frame aFrame = new Frame("Button2NewB");
aFrame.addWindowListener(new WL());
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~

內部類WL和main()方法是加入程序片的唯一兩個元素,程序片剩餘的部分則原封未動。事實上,我們通常將WL類和main()方法做一結小的改進複製和粘貼到我們自己的程序片裡(請記住創建內部類時通常需要一個外部類來處理它,形成它靜態地消除這個需要)。我們可以看到在main()方法裡,程序片明確地初始化和開始,因為在這個例子裡瀏覽器不能為我們有效地運行它。當然,這不會提供全部的瀏覽器調用stop()和destroy()的行為,但對大多數的情況而言它都是可接受的。如果它變成一個麻煩,我們可以:

(1) 使程序片句柄為一個靜態類(以代替局部可變的main()),然後:

(2) 在我們調用System.exit()之前在WindowAdapter.windowClosing()中調用applet.stop()和applet.destroy()。

注意最後一行:

aFrame.setVisible(true);

這是Java 1.1 AWT的一個改變。show()方法不再被支持,而setVisible(true)則取代了show()方法。當我們在本章後面部分學習Java Beans時,這些表面上易於改變的方法將會變得更加的合理。

這個例子同樣被使用TextField修改而不是顯示到控制檯或瀏覽器狀態行上。在開發程序時有一個限制條件就是程序片和應用程序我們都必須根據它們的運行情況選擇輸入和輸出結構。

這裡展示了Java 1.1 AWT的其它小的新功能。我們不再需要去使用有錯誤傾向的利用字符串指定BorderLayout定位的方法。當我們增加一個元素到Java 1.1版的BorderLayout中時,我們可以這樣寫:

aFrame.add(applet, BorderLayout.CENTER);

我們對位置規定一個BorderLayout的常數,以使它能在編譯時被檢驗(而不是對老的結構悄悄地做不合適的事)。這是一個顯著的改善,並且將在這本書的餘下部分大量地使用。

將窗口接收器變成匿名類

任何一個接收器類都可作為一個匿名類執行,但這一直有個意外,那就是我們可能需要在其它場合使用它們的功能。但是,窗口接收器在這裡僅作為關閉應用程序窗口來使用,因此我們可以安全地製造一個匿名類。然後,main()中的下面這行代碼:

aFrame.addWindowListener(new WL());

會變成:

aFrame.addWindowListener(new WindowAdapter() { //創建匿名類接收器對象,aFrame為事件源
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

這有一個優點就是它不需要其它的類名。我們必須對自己判斷是否它使代碼變得易於理解或者更難。不過,對本書餘下部分而言,匿名內部類將通常被使用在窗口接收器中。

將程序片封裝到JAR文件裡

一個重要的JAR應用就是完善程序片的裝載。在Java 1.0版中,人們傾向於試法將它們的代碼填入到單個的程序片類裡,因此客戶只需要單個的服務器就可適合下載程序片代碼。但這不僅使結果凌亂,難以閱讀(當然維護也然)程序,但類文件一直不能壓縮,因此下載從來沒有快過。

JAR文件將我們所有的被壓縮的類文件打包到一個單個兒的文件中,再被瀏覽器下載。現在我們不需要創建一個糟糕的設計以最小化我們創建的類,並且用戶將得到更快地下載速度。

仔細想想上面的例子,這個例子看起來像Button2NewB,是一個單類,但事實上它包含三個內部類,因此共有四個。每當我們編譯程序,我會用這行代碼打包它到一個JAR文件:

jar cf Button2NewB.jar *.class

這是假定只有一個類文件在當前目錄中,其中之一來自Button2NewB.java(否則我們會得到特別的打包)。

現在我們可以創建一個使用新文件標籤來指定JAR文件的HTML頁,如下所示:

<head><title>Button2NewB Example Applet</title></head>
<body>
  <applet code="Button2NewB.class"
  archive="Button2NewB.jar"
  width=200 height=150>
  </applet>
</body>

與HTML文件中的程序片標記有關的其他任何內容都保持不變。

java基礎技術提升篇:java AWT

java基礎技術提升篇:java AWT

"

相關推薦

推薦中...