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

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

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

    posts - 64,  comments - 9,  trackbacks - 0
    作為一個 Java 程序員,從論壇上感受到使用 Java 開發(fā)程序的人越來多,心中不免欣慰。但是,同樣是從論壇中,看到多數(shù)人提到 Java 就以為是網(wǎng)絡(luò)開發(fā)——不是這樣的,Java 也可以開發(fā)應(yīng)用程序,而且可以開發(fā)出漂亮的圖形用戶界面的應(yīng)用程序,也就是 Windows/XWindow 應(yīng)用程序。因此,我寫下這篇文章,希望能帶你進(jìn)入Java 圖形用戶界面設(shè)計之門。
      一. AWT 和 SWING
      AWT 和 SWING 是 Java 設(shè)計 GUI 用戶界面的基礎(chǔ)。與 AWT 的重量級組件不同,Swing 中大部分是輕量級組件。正是這個原因,Swing 幾乎無所不能,不但有各式各樣先進(jìn)的組件,而且更為美觀易用。所以一開始使用 AWT 的程序員很快就轉(zhuǎn)向使用 Swing 了。
      那為什么 AWT 組件沒有消亡呢?因為 Swing 是架構(gòu)在 AWT 之上的,沒有 AWT 就沒有 Swing。所以程序員可以根據(jù)自己的習(xí)慣選擇使用 AWT 或者是 Swing。但是,最好不要二者混用——除開顯示風(fēng)格不同不說,還很可能造成層次 (Z-Order) 錯亂,比如下例:
      /**
      * TestPanels.java
      * @author Fancy
      */
      import javax.swing.*;
      import java.awt.*;
      public class TestPanels extends JFrame {
      public TestPanels() {
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      JPanel panel = new JPanel();
      for (int i = 0; i < 2; i++) {
      panel.add(new JButton("Button 00" + i));
      }
      JTextArea textArea = new JTextArea(5, 15);
      textArea.setLineWrap(true);
      JScrollPane scrollPane = new JScrollPane(textArea);
      getContentPane().add(panel, BorderLayout.NORTH);
      getContentPane().add(scrollPane, BorderLayout.CENTER);
      pack();
      }
      public static void main(String[] args) {
      TestPanels tp = new TestPanels();
      tp.show();
      }
      }
      運行這個程序,并用鼠標(biāo)拖動那個名為“cover”的子窗口,我們會發(fā)現(xiàn)一個非常有趣的現(xiàn)象,如圖:
       
      顯然 cover 子窗口是在 controls 子窗口之上的,但是它只罩蓋住了 Swing Button,沒有罩蓋住 AWT Button。再看一會兒,你是不是有這樣一種感覺:Swing Button 是“畫”上去的,而 AWT Button 則是“貼”上去的。這就是二者混用造成層次錯亂的一個例子。
      Swing 組件有美觀、易用、組件量大等特點,也有缺點——使用 Swing 組件的程序通常會比使用 AWT 組件的程序運行更慢。但是大家都還是更喜歡用 Swing 組件,原因何在?因為隨著計算機硬件的升級,一點點速度已經(jīng)不是問題。相反的,用戶更需要美觀的用戶界面,開發(fā)人員則更需要易用的開發(fā)組件。
      ——好,我這就來教你使用 Swing 組件開發(fā)圖形用戶界面的 Java 應(yīng)用程序。
      二. 框架、監(jiān)聽器和事件
      框架 (Frame) 是 Java 圖形用戶界面的基礎(chǔ),它就是我們通常所說的窗口,是 Windows/XWindow 應(yīng)用程序的典型特征。說到 Windows/XWindow,大家很容易聯(lián)想到“事件 (Event) 驅(qū)動”。Java 的圖形用戶界面正是事件驅(qū)動的,并且由各種各樣的監(jiān)聽器 (Listener) 負(fù)責(zé)捕捉各種事件。
      如果我們需要對某一個組件的某種事件進(jìn)行捕捉和處理時,就需要為其添加監(jiān)聽器。比如,我們要在一個窗口 (JFrame) 激活時改變它的標(biāo)題,我們就需要為這個窗口 (JFrame 對象) 添加一個可以監(jiān)聽到“激活窗口”這一事件的監(jiān)聽器——WindowListener。
      怎么添加監(jiān)聽器呢?這通常由組件類提供的一個 addXXXXXListener 的方法來完成。比如 JFrame 就提供有 addWindowListener 方法添加窗口監(jiān)聽器 (WindowListener)。
      一個監(jiān)聽器常常不只監(jiān)聽一個事件,而是可以監(jiān)聽相關(guān)的多個事件。比如 WindowListener 除了監(jiān)聽窗口激活事件 (windowActivate) 之外,還可以監(jiān)聽窗口關(guān)閉事件 (windowClosing) 等。那么這些事件怎么區(qū)分呢?就靠重載監(jiān)聽器類 (Class) 的多個方法 (Method) 了,監(jiān)聽器監(jiān)聽到某個事件后,會自動調(diào)用相關(guān)的方法。我們只要重載這個方法,就可以處理相應(yīng)的事件了。
      不妨先看一個例子:
      /**
      * TestFrame.java
      * @author Fancy
      */
      import javax.swing.*;
      import java.awt.event.*;
      public class TestFrame extends JFrame {
      private int counter = 0;
      public TestFrame(){
      /* 使用匿名類添加一個窗口監(jiān)聽器 */
      addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
      System.out.println("Exit when Closed event");
      System.exit(0); //退出應(yīng)用程序
      }
      public void windowActivated(WindowEvent e){setTitle("Test Frame " + counter++); // 改變窗口標(biāo)題
      }
      });
      setResizable(false); // 設(shè)置窗口為固定大小
      setSize(200, 150);
      }
      public static void main(String[] args) {
      TestFrame tf = new TestFrame();
      tf.show();
      }
      }
      這個例子中,我們設(shè)計了一個窗口類(public class TestFrame extends JFrame { ...),并且為這個窗口添加了一個窗口監(jiān)聽器 (addWindowListener(new WindowAdapter() ...)。而我們添加的這個窗口監(jiān)聽器主要監(jiān)聽了兩個事件:窗口關(guān)閉 (public void windowClosing(WindowEvent e) ...) 和窗口激活 (public void windowActivated(WindowEvent e) ...)。在窗口關(guān)閉事件中我們退出了整個應(yīng)用程序(System.exit(0);),而在窗口激活事件中,我們改變了窗口的標(biāo)題 (setTitle("Test Frame " + counter++);)。最后,我們在 main 方法中顯示了這窗口類的一個實例,運行得到下圖所示的結(jié)果:
       
      這個程序的運行結(jié)果就是一個什么東西都沒有加的框架,也就是一個空窗口。那么,你知道顯示一個窗口最主要的幾句代碼嗎?不知道沒關(guān)系,我來告訴你,顯示一個窗口只需要做三件事:生成實例(對象) -> 設(shè)置大小 -> 顯示,相應(yīng)的,就是下面的三句代碼:
      JFrame frame = new JFrame("Frame's Title");
      frame.setSize(400, 300);
      frame.show();
      也許你會說:第一句的意思我清楚,第三句的意思我也明白,為什么一定要第二句呢?其實想想也就明白了,叫你畫一個沒法有大小的矩形你能畫出來嗎?不能。同樣,沒有大小的窗口,怎么顯示?所以我們需要用 setSize(int width, int height) 方法為其設(shè)置大小。我們還有另一種方法:用 JFrame 的 pack() 方法讓它自己適配一個大小。pack() 在多數(shù)時候是令人滿意的,但有時,它也會讓你哭笑不得——多試試就知道了。
      在 JFrame 中,我們使用 addWindowListener 方法加入一個監(jiān)聽器 WindowListener (addWindowListener(new WindowAdapter() ...) 去監(jiān)聽發(fā)生在 JFrame 上的窗口事件。WindowListener 是一個接口,在 java.awt.event 這個包中,但是上例中好象并沒有使用 WindowListener,而是使用的 WindowsAdapter 吧,這是怎么回事?
      WindowAdapter 是 WindowsListener 接口的一個最簡單的實現(xiàn),也在包 java.awt.event 中。如果我們直接使用 WindowListener 產(chǎn)生一個匿名類,需要實現(xiàn)它的每一個方法 (一共 7 個)。但 WindowAdapter 作為 WindowListener 最簡單的實現(xiàn),已經(jīng)實現(xiàn)了它的每一個方法為空方法 (即只包含空語句,或者說沒有語句的方法)。用 WindowAdapter 就只需要重載可能用到的方法 (上例中只有 2 個) 就行了,而不需要再去實現(xiàn)每一個方法。優(yōu)點顯而易見——減少代碼量。
      在 JFrame 上發(fā)生的窗口事件 (WindowEvent) 包括:
      windowActivated(WindowEvent e) 窗口得到焦點時觸發(fā)
      windowClosed(WindowEvent e) 窗口關(guān)閉之后觸發(fā)
      windowClosing(WindowEvent e) 窗口關(guān)閉時觸發(fā)
      windowDeactivated(WindowEvent e) 窗口失去焦點時觸發(fā)
      windowDeiconified(WindowEvent e) 
      windowIconified(WindowEvent e) 
      windowOpened(WindowEvent e) 窗口打開之后觸發(fā)
      上例重載了其中兩個方法。如果在上例運行產(chǎn)生的窗口和另外一個應(yīng)用程序窗口之間來回切換 (在 Windows 操作系統(tǒng)中你可以使用 Alt+Tab 進(jìn)行切換)……試試看,你發(fā)現(xiàn)了什么?有沒有現(xiàn)我們的示例窗口標(biāo)題上的數(shù)字一直在增加,這便是在 windowActivated 事件中 setTitle("Test Frame " + counter++); 的功勞。
      而另一個事件處理函數(shù) windowClosing 中的 System.exit(0) 則保證了當(dāng)窗口被關(guān)閉時退出當(dāng)前的 Java 應(yīng)用程序。如果不作這樣的處理會怎樣呢?試驗之后你會發(fā)現(xiàn),窗口雖然關(guān)閉了,但程序并沒有結(jié)束,但此時,除了使用 ^C 強行結(jié)束之外,恐怕也沒有其它辦法了。所以,這一點非常重要:如果你想在關(guān)閉窗口的時候退出應(yīng)用程序,需要你自己寫代碼處理 windowClosing 事件。……也不盡然,其實還有另外一個更簡單的辦法,讓 JFrame 自己處理這件事——你只需要如下調(diào)用 JFrame 的 setDefaultCloseOperation 即可: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      我們可以在 JFrame 對象中添加 AWT 或者 Swing 組件。但是,雖然它有 add 方法,卻不能直接用于添加組件,否則會拋出異常——不信就試試。造成這個現(xiàn)象的原因只有一個解釋:JFrame 不是一個容器,它只是一個框架。那么,應(yīng)該怎么添加組件呢?

      JFrame 有一個 Content Pane,窗口是顯示的所有組件都是添加在這個 Content Pane 中。JFrame 提供了兩個方法:getContentPane 和 setContentPane 就是用于獲取和設(shè)置其 Content Pane 的。通常我們不需要重新設(shè)置 JFrame 的 Content Pane,只需要直接獲取


    四. 文本輸入框、密碼輸入框
      文本輸入框包括兩種,單行文本輸入框 (JTextField) 和多行文本輸入框 (JTextArea)。密碼輸入框則只有一種 (JPasswordField)。JPasswordField 是 JTextField 的子類,它們的主要區(qū)別是 JPasswordField 不會顯示出用戶輸入的東西,而只會顯示出程序員設(shè)定的一個固定字符,比如 '*'。
      下面的示例圖和代碼是 JTextField、JPasswordField 和 JTextArea 的示例:
       
      /**
      * TestTexts.java
      * @author Fancy
      */
      import javax.swing.*;
      import javax.swing.event.*;
      public class TestTexts extends JFrame {
      private JLabel label = new JLabel("Status");
      private JTextField textField;
      private JPasswordField pwdField;
      private JTextArea textArea;
      public TestTexts() {
      super("Test Texts");
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      getContentPane().setLayout(new java.awt.FlowLayout());
      textField = new JTextField(15);
      /* 監(jiān)聽文本光標(biāo)移動事件 */
      textField.addCaretListener(new CaretListener() {
      public void caretUpdate(CaretEvent e) {
      // 如果改變了內(nèi)容,就可以即時更新 label 顯示的內(nèi)容
      label.setText(textField.getText());
      }
      });
      pwdField = new JPasswordField(15);
      pwdField.setEchoChar('#');
      textArea = new JTextArea(5, 15);
      textArea.setLineWrap(true);
      getContentPane().add(textField);
      getContentPane().add(pwdField);
      getContentPane().add(textArea);
      getContentPane().add(label);
      setSize(200, 200);
      }
      public static
      void main(String[] args) {
      TestTexts tt = new TestTexts();
      tt.show();
      }
      }
      上例中,我們構(gòu)造了一個寬度為 15 個字符的單行文本框 (textField = new JTextField(15);),并使用 addCaretListener 方法添加了一個 CaretListener (textField.addCaretListener ...)。CaretListener 監(jiān)聽文本光標(biāo)的移動事件。當(dāng)用戶使用鍵盤、鼠標(biāo)等移動了文本光標(biāo)在 JTextField 中的位置時觸發(fā)這個事件。我們需要重載 caretUpdate(CaretEvent e) 對事件進(jìn)行處理 (public void caretUpdate(CaretEvent e) ...)。這樣,我們可以在這里做類似 VB 中 TextBox 的 OnChange 事件中做的事情。
      JTextField 有 5 個構(gòu)造方法,常用其中的四個:
      JTextField()
      JTextField(int columns),如上例 textField = new JTextField(15);
      JTextField(String text)
      JTextField(String text, int columns)
      其中,參數(shù) text 是單行文本框的初始內(nèi)容,而 columns 指定了單行文本框的寬度,以字符為單位。JTextField 中的文本內(nèi)容可以用 getText() 方法獲得。也可以用 setText 方法指定 JTextField 中的文本內(nèi)容。
      JPasswordField 是 JTextField 的子類,其構(gòu)造方法也是類似的。JPasswordField 提供了 setEchoChar(char ch) 方法設(shè)置為了隱藏密碼而顯示的字符,默認(rèn)為 '*' 字符,上例中則設(shè)置為了 '#' 字符 (pwdField.setEchoChar('#');)。與 JTextField 一樣,JPasswordField 也用 getText 方法和 setText 獲得或者設(shè)置文本內(nèi)容 (當(dāng)然在用戶界面上是隱藏的)。
      JTextField 是單行文本框,不能顯示多行文本,如果想要顯示多行文本,就只好使用多行文本框 JTextArea 了。JTextArea 有六個構(gòu)造方法,常用的也是四個:
      JTextArea()
      JTextArea(int rows, int columns)
      JTextArea(String text)
      JTextArea(String text, int rows, int columns) 
      text 為 JTextArea 的初始化文本內(nèi)容;rows 為 JTextArea 的高度,以行為單位;columns 為 JTextArea 的寬度,以字符為單位。如上例中就構(gòu)造了一個高 5 行,寬 15 個字符的多行文本框 (textArea = new JTextArea(5, 15);)。
      多行文本框默認(rèn)是不會自動折行的 (不過可以輸入回車符換行),我們可以使用 JTextArea 的 setLineWrap 方法設(shè)置是否允許自動折行。setLineWrap(true) 是允許自動折行,setLineWrap(false) 則是不允許自動折行。多行文本框會根據(jù)用戶輸入的內(nèi)容自動擴展大小,不信,自己做個實驗——如果不自動折行,那么多行文本框的寬度由最長的一行文字確定的;如果行數(shù)據(jù)超過了預(yù)設(shè)的行數(shù),則多行文本框會擴展自身的高度去適應(yīng)。換句話說,多行文本框不會自動產(chǎn)生滾動條。怎么辦?后面講到滾動窗格 (JScrollPane) 的時候,你就知道了。
      多行文本框里文本內(nèi)容的獲得和設(shè)置,同樣可以使用 getText 和 setText 兩個方法來完成。
      五. 窗格、滾動窗格和布局管理
      窗格 (JPanel) 和滾動窗格 (JScrollPane) 在圖形用戶界面設(shè)計中大量用于各種組件在窗口上的布置和安排。這里所謂的布置和安排,就是布局 (Layout),因此不得不先說說布局。
      將加入到容器(通常為窗口等) 的組件按照一定的順序和規(guī)則放置,使之看起來更美觀,這就是布局。布局由布局管理器 (Layout Manager) 來管理。那么,我們在什么時候應(yīng)該使用布局管理器?應(yīng)用選擇哪種布局管理器?又該怎樣使用布局管理器呢?
      往往,我們設(shè)計一個窗口,其中是要添加若干組件的。為了管理好這些管理的布局,我們就要使用布局管理器。比如說,設(shè)計一個簡單的編輯器,這個編輯器中只需要放置兩個按鈕和一個多行文本框。這些組件是讓 Java 自己任意安排呢?還是按照一定的位置關(guān)系較規(guī)范的安排呢?當(dāng)然應(yīng)該選擇后者。那么,為了按照一定的位置關(guān)系安排這些組件,我們就需要用到布局管理器了。
      然后我們遇到了一個選擇題——使用哪種布局管理器。為此,我們首先要知道有些什么布局管理器,它們的布局特點是什么。常用的布局管理器有: FlowLayout、BorderLayout、GridLayout、BoxLayout 等,其中 FlowLayout 和 BorderLayout 最常用,本文主要也就只談?wù)勥@兩種布局管理器。下面列表說明它們的布局特點:
       
      就上述的編輯器為例,如果選用 FlowLayout,那么兩個按鈕和一個多行文本框就會排列在一行——當(dāng)然這是窗口足夠?qū)挼那闆r;如果窗口稍窄一些,則可能分兩行排列,第一行有兩個按鈕,而第二行是多行文本框——這是最理想的情況;如果窗口再窄一些,就可能分三行排列,第一行和第二行分別放置一個按鈕,第三行放置多行文本框。因此,如果窗口大小可以改變,那么三個組件的位置關(guān)系也可能隨著窗口大小的變化而變化。所以,F(xiàn)lowLayout 不適用。其實上面所舉的例程中,大部分都是用的 FlowLayout,那是因為我們沒有要求組件的布局。
      如果選用 BorderLayout 的情況又如何呢?我們可以試著加入一個窗格 (JPanel,稍后講解),并將兩個按鈕放置在其中,然后將這個窗格加入到 BorderLayout 的北部 (即上部);再將多行文本框加入到 BorderLayout 中部。結(jié)果類似使用 FlowLayout 的第二種可能,是最理想的情況。而且,如果改變窗口大小,它們的位置關(guān)系仍然是北-中的關(guān)系,不會隨之改變。
      剩下的兩種布局管理器,加以窗格 (JPanel) 的配合,也能夠很好的安排上述編輯器所需的三個組件。但是由于它們的使用稍為復(fù)雜一些,所以就不講了。下面就講講如何使用 FlowLayout 和 BorderLayout。
      任何布局管理器,都需要用在容器上,比如 JFrame 的 Content Pane 和下面要說的 JPanel 都是容器。容器組件提供了一個 setLayout 方法,就是用來改變其布局管理器的。默認(rèn)情況下,JFrame 的 Content Pane 使用的是 BorderLayout,而 JPanel 使用的是 FlowLayout。但不管怎樣,我們都可以調(diào)用它們的 setLayout 方法來改變其布局管理器。比如上述的編輯器中,我們要讓窗口 (JFrame 對象,假設(shè)為 frame) 使用 BorderLayout,就可以使用 frame.getContentPane().setLayout(new BorderLayout()); 來改變其布局管理器為一個新的 BorderLayout 對象。
      然后,我們對布局管理器的直接操作就結(jié)束了,剩下的只需要往容器里添加組件。如果使用 FlowLayout,我們只需要使用容器的 add(Component c) 方法添加組件就行了。但是,如果使用 BorderLayout 就不一樣了,因為要指定是把組件添加到哪個區(qū)域啊。那我們就使用容器的 add(Component c, Object o) 方法添加組件,該方法的第二個參數(shù)就是指明添加到的區(qū)域用的。例如,上述編輯器中要添加一個多行文本框到 BorderLayout 的中部,就可以用 frame.getContentPane().add(new JTextArea(5, 15), BorderLayout.CENTER) 來實現(xiàn)。
      BorderLayout 的五個區(qū)域分別是用下列五個常量來描述的:
      BorderLayout.EAST 東
      BorderLayout.SOUTH 南
      BorderLayout.WEST 西
      BorderLayout.NORTH 北
      BorderLayout.CENTER 中
      剛才已經(jīng)提到了使用 JPanel。JPanel 作為一個容器,可以包容一些組件,然后將這個 JPanel 對象作為一個組件添加到另一個容器 (稱作父容器) 中。這個功能有什么好處呢?
      上面不是提到 BorderLayout 的一個區(qū)域中只能添加一個組件嗎?但是我們的編輯器需要添加兩個按鈕到它的北部,怎么辦?上面的例子中,我們就是用的一個 JPanel 包容了這兩個按鈕,然后再將這個 JPanel 對象作為一個組件添加到設(shè)置布局管理器為 BorderLayout 的 Content Pane 中。
      上面說到各布局管理器的布局特點的時候,幾乎每一種都是一個區(qū)域只能添加一個組件,那我們想添加多個組件到一個區(qū)域的時候,就要用到 JPanel 了。如果還沒有明白,稍后看一段程序可能更易于理解。
    posted on 2009-12-24 15:39 super_nini 閱讀(450) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    <2009年12月>
    293012345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    常用鏈接

    留言簿

    隨筆檔案

    文章檔案

    相冊

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲色图黄色小说| 久久亚洲AV成人无码国产| 在线精品亚洲一区二区| 亚洲免费网站在线观看| 亚洲久本草在线中文字幕| 13小箩利洗澡无码视频网站免费 | 亚洲理论片在线观看| 最近中文字幕mv免费高清视频8 | 亚洲一区二区三区播放在线| 在线a免费观看最新网站| 亚洲一级毛片视频| 免费激情视频网站| 羞羞漫画在线成人漫画阅读免费| 亚洲一本大道无码av天堂| 日本高清不卡aⅴ免费网站| 久久亚洲精品中文字幕无码| 啦啦啦完整版免费视频在线观看| 亚洲伊人久久大香线蕉啊| 免费观看黄网站在线播放| 国产精品亚洲一区二区三区| 亚洲片一区二区三区| 精品国产污污免费网站| 亚洲日韩中文字幕天堂不卡| 在线播放免费人成视频在线观看| 国产偷国产偷亚洲高清人| 亚洲国产日韩在线视频| 18国产精品白浆在线观看免费| 亚洲变态另类一区二区三区| 久久久久亚洲?V成人无码| 最近免费中文字幕大全免费| 亚洲久热无码av中文字幕| 国产gv天堂亚洲国产gv刚刚碰 | 日韩在线看片免费人成视频播放| 免费国产a理论片| 亚洲第一视频网站| 在线播放免费播放av片| 成人爽a毛片免费| 亚洲中文无码mv| 亚洲国产精品成人精品无码区| 野花高清在线观看免费3中文| 亚洲免费视频一区二区三区|