1. 程式人生 > >Swing元件專案開發知識筆記

Swing元件專案開發知識筆記

UI 元件簡介

在開始學習 Swing 之前,必須回答針對真正初學者的一個問題:什麼是 UI?初學者的答案是使用者介面。但是因為本教程的目標是要保證您不再只是個初學者,所以我們需要比這個定義更高階的定義。

所以,我再次提出這個問題:什麼是 UI?您可能把它定義成您按下的按鈕、打字的位址列 、開啟和關閉的視窗,等等,這些都是 UI 的元素,但是除了在螢幕上看到的這些之外,還有更多都是 UI 元素。比如滑鼠、鍵盤、音量、螢幕顏色、使用的字型,以及一個物件相對於另一個物件的位置,這些都包含在 UI 之中。實際上,在計算機和使用者的互動之中扮演角色的任何物件都是 UI 的組成部分。這看起來足夠簡單,但是您應當驚訝的是,有許多人和大型公司已經為它努力了很多年。實際上,現在有的大學專業的惟一課程就是研究這種互動。

Swing 的角色

Swing 是 Java 平臺的 UI —— 它充當處理使用者和計算機之間全部互動的軟體。它實際上充當使用者和計算機內部之間的中間人。Swing 到底是如何做這項工作的呢?它提供了處理前面一節中描述的 UI 各方面內容的機制:

  • 鍵盤:Swing 提供了捕捉使用者輸入的方法。
  • 顏色:Swing 提供改變在螢幕上看到的顏色的方法。
  • 打字的位址列:Swing 提供了文字元件,處理所有普通任務。
  • 音量:Swing 不太擅長。

無論如何,Swing 為您提供了建立自己的 UI 所需要的所有工具

MVC

Swing 甚至走得更遠一步,在基本的 UI 原則之上又放上了一個公共的設計模式。這個設計模式叫做模型

-檢視-控制器(Model-View-ControllerMVC),它試圖把角色分開MVC 讓負責顯示的程式碼、處理資料的程式碼、對互動進行響應並驅動變化的程式碼彼此分離。

有點迷惑?如果我為這個設計模式提供一個現實世界的非技術性示例,它就比較容易了。請想像一次時裝秀。把秀場當成 UI,假設服裝就是資料,是展示給使用者的計算機資訊。現在,假設這次時裝秀中只有一個人。這個人設計服裝、修改服裝、同時還在 T 臺上展示這些服裝。這看起來可不是一個構造良好的或有效率的設計。

現在,假設同樣的時裝秀採用 MVC 設計模式。這次不是一個人做每件事,而是將角色分開。時裝模特(不要與 MVC 縮寫中的模型混淆)展示服裝。他們扮演的角色是檢視。他們知道展示服裝(資料的)適當方法,但是根本不知道如何建立或設計服裝。另一方面,時裝設計師充當控制器。時裝設計師對於如何在

T 臺上走秀沒有概念,但他能建立和操縱服裝。時裝模特和設計師都能獨立地處理服裝,但都有自己的專業領域。

這就是 MVC 設計模式背後的概念:讓 UI 的每個方面處理它擅長的工作。如果您仍然不明白,那麼教程後面的示例有望消除您的迷惑 —— 但是在您繼續進行的時候,請記住基本的原則:用可視元件顯示資料,同時讓其他類操縱資料。

JComponent

Swing 的整個可視元件庫的基礎構造塊是 JComponent。它是所有元件的父類。它是一個抽象類,所以不能建立 JComponent,但是作為類層次結構的結果,從字面意義來說它包含了數百個函式,Swing 中的每個元件都可以使用這些函式。顯然,有些概念要比其他概念重要,所以對於本教程,需要學習的重要的東西是:

  • JComponent 不僅是 Swing 元件的基類,還是定製元件的基類(有關的更多資訊在“中級 Swing”教程中)。
  • 它為所有元件提供了繪製的基礎架構 —— 一些方便進行元件定製的東西(同樣,在“中級 Swing”中,有關於這個主題的更多資訊)。
  • 它知道如何處理所有的鍵盤按鍵。所以類只需要偵聽特定的鍵。
  • 它包含 add() 方法,可以新增其他 JComponent。換種方式來看,可以把任意 Swing 元件新增到其他任何 Swing 元件,從而構造巢狀元件(例如,JPanel 包含 JButton,甚至包含一些古怪的組合,例如 JMenu 包含 JButton)。

簡單的swing小部件

JLabel

Swing 庫中最基礎的元件是 JLabel。它所做的正是您所期望的:呆在那兒,看起來很漂亮,描述其他元件。下圖顯示了的 JLabel 實際應用:

JLabel

不太吸引人,但是仍然有用。實際上,在整個應用程式中,不僅把 JLabel 用作文字描述,還將它用作圖片描述。每當在 Swing 應用程式中看到圖片的時候,它就有可能是 JLabel。JLabel 對於 Swing 初學者來說沒有許多意料之外的方法。基本的方法包括設定文字、圖片、對齊以及標籤描述的其他元件:

  • get/setText(): 獲取/設定標籤的文字。
  • get/seticon(): 獲取/設定標籤的圖片。
  • get/setHorizontalAlignment(): 獲取/設定文字的水平位置。
  • get/setVerticalAlignment(): 獲取/設定文字的垂直位置。
  • get/setDisplayedMnemonic(): 獲取/設定標籤的訪問鍵(下劃線文字)。
  • get/setLableFor(): 獲取/設定這個標籤附著的元件,所以當用戶按下 Alt+訪問鍵時,焦點轉移到指定的元件。

JButton

Swing 中的基本動作元件 JButton,是與每個視窗中都能看到的 OK 和 Cancel 一樣的按鈕;這些按鈕所做的正是您希望它們做的工作 —— 在單擊它們之後,將發生一些事情。到底會發生什麼呢?您必須定義發生的內容(請參閱 事件,以獲得更多資訊)。一個 JButton 例項看起來如下所示:

JButton

用來改變 JButton 屬性的方法與 JLabel 的方法類似(您可能發現,在大多數 Swing 元件中,這些屬性都類似)。它們控制文字、圖片和方向:

  • get/setText(): 獲取/設定標籤的文字。
  • get/seticon(): 獲取/設定標籤的圖片。
  • get/setHorizontalAlignment(): 獲取/設定文字的水平位置。
  • get/setVerticalAlignment(): 獲取/設定文字的垂直位置。
  • get/setDisplayedMnemonic(): 獲取/設定訪問鍵(下劃線字元),與 Alt 按鈕組合時,造成按鈕單擊。

除了這些方法,我還要介紹 JButton 包含的另外一組方法。這些方法利用了按鈕的所有不同狀態。狀態是對元件進行描述的一個屬性,通常採用真/假設定。在 JButton 中,可以包含以下可能狀態:活動/不活動、選中/沒選中、滑鼠經過/滑鼠離開、按下/沒按下,等等。另外,可以組合這些狀態,例如按鈕可以在滑鼠經過的同時被選中。現在您可能會問自己用這些狀態到底要做什麼。作為示例,請看看您的瀏覽器上的後退按鈕。請注意在滑鼠經過它的時候,圖片是如何變化的,在按下該按鈕時,圖片又是如何變化的。這個按鈕利用了不同的狀態。每個狀態採用不同的圖片,這是提示使用者互動正在進行的一種普遍並且有效的方式。JButton 上的狀態方法是:

  • get/setDisabledIcon()
  • get/setDisableSelectedIcon()
  • get/setIcon()
  • get/setPressedIcon()
  • get/setRolloverIcon()
  • get/setRolloverSelectedIcon()
  • get/setSelectedIcon()

JTextField

Swing 中的基本文字元件是 JTextField,它允許使用者在 UI 中輸入文字。我肯定您熟悉文字欄位:要掌握本教程,則必須使用一個文字欄位輸入使用者名稱和口令。您輸入文字、刪除文字、選中文字、把文字四處移動 —— Swing 替您負責所有這些工作。作為 UI 開發人員,利用 JJTextField 時,實際上並不需要做什麼。

在任何情況下,這是 JTextField 實際使用時看起來的樣子:

JTextField

在處理 JTextField 時,只需要關注一個方法 —— 這應當是很明顯的,這個方法就是設定文字的方法: get/setText(),用於獲取/設定 JTextField 中的文字。

JFrame

迄今為止,我介紹了 Swing 的三個基本構造塊:標籤、按鈕和文字欄位;但是現在需要個地方放它們,希望使用者知道如何處理它們。JFrame 類就是做這個的——它是一個容器,允許您把其他元件新增到它裡面,把它們組織起來,並把它們呈現給使用者。它有許多其他好處,但是我認為先看看它的圖片最簡單:

JFrame

JFrame 實際上不僅僅讓您把元件放入其中並呈現給使用者。比起它表面上的簡單性,它實際上是 Swing 包中最複雜的元件。為了最大程度地簡化元件,在獨立於作業系統的 Swing 元件與實際執行這些元件的作業系統之間,JFrame 起著橋樑的作用。JFrame 在本機作業系統中是以視窗的形式註冊的,這麼做之後,就可以得到許多熟悉的作業系統視窗的特性:最小化/最大化、改變大小、移動。但是對於本教程的目標來說,把 JFrame 當作放置元件的調色盤就足夠了。可以在 JFrame 上呼叫的一些修改屬性的方法是:

  • get/setTitle(): 獲取/設定幀的標題。
  • get/setState(): 獲取/設定幀的最小化、最大化等狀態。
  • is/setVisible(): 獲取/設定幀的可視狀態,換句話說,是否在螢幕上顯示。
  • get/setLocation(): 獲取/設定幀在螢幕上應當出現的位置。
  • get/setsize(): 獲取/設定幀的大小。
  • add(): 將元件新增到幀中。

簡單應用程式

就像所有的“x 入門教程一樣,本教程也包含必不可少的 HelloWorld 演示。但這個示例不僅對觀察 Swing 應用程式如何工作有用,還對確保設定正確很有用。一旦使這個簡單的應用程式能夠成功執行,那麼之後的每個示例也將能夠執行。下圖顯示了完成後的示例:

HelloWorld 示例

第一步是建立類。將元件放在 JFrame 上的 Swing 應用程式需要繼承JFrame 類,如下所示:

publicclass HelloWorld extends JFrame 

這樣做之後,就得到上面描述的所有 JFrame 屬性,最重要的是作業系統對視窗的本機支援。下一步是把元件放在螢幕上。在這個示例中,使用了一個 null 佈局。在教程的後面部分,您將學到更多關於佈局和佈局管理器的內容。但對於這個示例,可以用數字表示 JFrame 上的畫素位置:

public HelloWorld() 
   { 
super(); 
this.setSize(300, 200); 
this.getContentPane().setLayout(null); 
this.add(getJLabel(), null); 
this.add(getJTextField(), null); 
this.add(getJButton(), null); 
this.setTitle("HelloWorld"); 
   } 
private javax.swing.JLabel getJLabel() { 
if(jLabel == null) { 
         jLabel = new javax.swing.JLabel(); 
         jLabel.setBounds(34, 49, 53, 18); 
         jLabel.setText("Name:"); 
      } 
return jLabel; 
   } 
private javax.swing.JTextField getJTextField() { 
if(jTextField == null) { 
         jTextField = new javax.swing.JTextField(); 
         jTextField.setBounds(96, 49, 160, 20); 
      } 
return jTextField; 
   } 
private javax.swing.JButton getJButton() { 
if(jButton == null) { 
         jButton = new javax.swing.JButton(); 
         jButton.setBounds(103, 110, 71, 27); 
         jButton.setText("OK"); 
      } 
return jButton; 
   } 

現在元件都放在了 JFrame 上,並且需要在螢幕上顯示 JFrame,並讓應用程式可以執行。就像在所有的 Java 應用程式中一樣,必須新增一個 main 方法,才能讓 Swing 應用程式執行。在這個 main 方法中,只需要建立 HelloWorld 應用程式物件,然後呼叫其setVisible()即可:

publicstaticvoid main(String[] args) 
   { 
      HelloWorld w = new HelloWorld(); 
      w.setVisible(true); 
   } 

完成了!這就是建立應用程式的所有過程。

完整程式碼如下:

package cn.edu.jnu.www;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class HelloWorld extends JFrame{
 private JLabel jLabel;
 private JTextField jTextField;
 private JButton jButton;
 
public HelloWorld()
{
   super();
   this.setSize(300, 200);
   this.getContentPane().setLayout(null);
   this.add(getJLabel(), null);
   this.add(getJTextField(), null);
   this.add(getJButton(), null);
   this.setTitle("HelloWorld");
}

private javax.swing.JLabel getJLabel() {
   if(jLabel == null) {
      jLabel = new javax.swing.JLabel();
      jLabel.setBounds(34, 49, 53, 18);
      jLabel.setText("Name:");
   }
   return jLabel;
}

private javax.swing.JTextField getJTextField() {
   if(jTextField == null) {
      jTextField = new javax.swing.JTextField();
      jTextField.setBounds(96, 49, 160, 20);
   }
   return jTextField;
}

private javax.swing.JButton getJButton() {
   if(jButton == null) {
      jButton = new javax.swing.JButton();
      jButton.setBounds(103, 110, 71, 27);
      jButton.setText("OK");
   }
   return jButton;
}


public static void main(String[] args)
{
   HelloWorld w = new HelloWorld();
   w.setVisible(true);
}

}




附加的swing小部件(上)

JComboBox

在這一節中,我將介紹 Swing 庫中的其他全部元件、如何使用它們、它們看起來是什麼樣的,等等,這部分內容應當讓您更好地瞭解 Swing 為 UI 開發人員提供了什麼。

我們從 JComboBox 開始介紹。組合框與下拉選擇相似,區別在於使用組合框時使用者可以不從列表中選擇專案,還可以選擇一個(而且只有一個)專案。在某些版本的組合框中,還可以輸入自己的選擇。瀏覽器的位址列就是一個示例:它是一個允許輸入自己選項的組合框。以下是 JComboBox 在 Swing 中看起來的樣子:

JComboBox

JComboBox 的重要函式包括 JComboBox 包含的資料。需要有一種方法來設定 JComboBox 中的資料、修改資料、在使用者選擇時得到使用者的選擇。可以使用以下 JComboBox 方法:

  • addItem()新增一個專案到 JComboBox.
  • get/setSelectedIndex()獲取/設定 JComboBox 中選中專案的索引。
  • get/setSelectedItem()獲取/設定選中的物件。
  • removeAllItems()從 JComboBox 刪除所有物件。
  • remoteItem()從 JComboBox 刪除特定物件。

JTextField

JTextField 的一個細微變化是 JPasswordField,它允許您隱藏在文字欄位區域中顯示的字元。畢竟,在您輸入口令的時候,如果每個人都能看到,那可沒什麼好處?可能根本就不好,而且在私人資料如此脆弱的今天,您需要所有能夠得到的幫助。以下是 JPasswordField 在 Swing 中看起來的樣子:

JPasswordField

JPasswordField 上額外的“安全性”方法對 JTextField 的行為做了輕微改變,所以不能閱讀文字:

  • get/setEchoChar()獲取/設定每次字元輸入時在 JPasswordField 中顯示的字元。在獲取口令時,不會返回“回聲”,而是返回實際的字元。
  • getText() 不應當 使用這個函式,因為它會帶來可能的安全問題(String 會儲存在記憶體中,可能的堆疊轉儲會暴露口令)。
  • getPassword()這是從 JPasswordField 中獲得口令的恰當方法,因為它返回一個包含口令的 char[]。為了保證恰當的安全性,陣列應當被清為 0,以確保它不會保留在記憶體中。

 JCheckBox/JRadioButton

JCheckBox 和 JRadioButton 元件向用戶呈現選項,通常採用多選的格式。區別是什麼?從實踐的角度來說,它們沒有那麼不同。它們的行為方式相同。但是,在一般的 UI 實踐中,它們有細微差異:JRadioButton 通常組合在一起,向用戶呈現帶有必選答案的問題,而且這些答案具有強制性(這意味著問題只能有一個答案)。JRadioButton 的行為保證了這個用法。一旦選擇了JRadioButton,就不能取消對它的選擇,除非選擇了在同一組中的另外一個單選鈕。從效果上看,這就保證了選項的惟一和必選。JCheckBox 的不同在於,允許隨機地選擇/取消除選擇,並允許為問題選擇多個答案。

這裡是個示例。問題“您是男孩還是女孩!”有兩個惟一答案選項“男孩”或“女孩”。使用者必須選擇一個,不能同時選中。另一方面,問題“您的習慣是什麼?”的答案有“跑步”、“睡覺”或“閱讀”,不應當只允許為此問題選擇一個答案,因為人們可能有不止一個習慣。

把這些 JCheckBoxe 或 JRadioButton 捆綁成一組的類是 ButtonGroup 類。它允許把選項組織在一起(例如“男孩”和“女孩”),這樣,其中一個被選擇時,另外一個就自動取消選擇。

以下是 JCheckBox 和 JRadioButton 在 Swing 中看起來的樣子:

JCheckBox 和 JRadioButton

需要記住的重要的 ButtonGroup 方法是:

  • add()新增 JCheckBox 或 JRadioButton 到 ButtonGroup。
  • getElements()獲得 ButtonGroup 中的全部元件,允許對它們進行迭代,找到其中選中的那個。

 JMenu/JMenuItem/JMenuBar

JMenu、JMenuItem 和 JMenuBar 元件是在 JFrame 中開發菜單系統的主要構造塊。任何菜單系統的基礎都是 JMenuBar。它平淡而乏味,但卻是必需的,因為每個 JMenu 和 JMenuItem 都要用它構建。要用 setJMenuBar() 方法把 JMenuBar 附著到 JFrame。一旦將它附加到 JFrame 中,就可以新增所有想要的選單、子選單和選單項。

JMenu/JMenuItem 的區別看起來可能很明顯,但實際上,在幕後看起來並不像表面那樣。看看類的類層次結構,就知道JMenuJMenuItem 的子類。但是,在表面上,它們是有區別的:用 JMenu 包含其他 JMenuItem 和 JMenu;JMenuItem 在選中時觸發操作。

JMenuItem 也支援快捷鍵的概念。與您用過的大多數應用程式一樣,Swing 應用程式允許您按下 Ctrl+(某個鍵)來觸發一個操作,就像選中選單鍵本身一樣。想想用來剪下和貼上的快捷鍵 Ctrl+X 和 Ctrl+V。

除此之外,JMenu 和 JMenuItem 都支援訪問鍵。用 Alt 鍵與某個字母關聯,模擬選單本身的選擇(例如,在 Windows 中按下 Alt+F,然後按下 Alt+x 就可以關閉應用程式)。

以下是包含 JMenu 和 JMenuItem 的 JMenuBar 在 Swing 中的樣子:

JMenuBar、JMenu 和 JMenuItem

這些類需要的重要方法是:

  • JMenuItem and JMenu:
    • get/setAccelerator()獲取/設定用作快捷鍵的 Ctrl+鍵。
    • get/setText()獲取/設定選單的文字。
    • get/setIcon()獲取/設定選單使用的圖片。
  • JMenu 專用:
    • add()新增另外一個 JMenu 或 JMenuItem 到 JMenu(建立巢狀選單)。

 JSlider

在應用程式中 JSlider 支援數值變化。它是一種迅速而簡單的方式,不僅能讓使用者以可視形式獲得他們當前選擇的反饋,還能得到可以接受的值的範圍。想像一下這種情況:可以提供一個文字欄位,允許使用者輸入值,但是這樣做就帶來了額外的麻煩,要確保輸入的值是數字,還要確保數字符合要求的數值範圍。例如,如果有一個金融 Web 站點,它向您提問要在股票上投資的百分比,那麼您不得不檢查在文字欄位中輸入的值,以確保它們是數字,而且在 0 到 100 之間。如果換用 JSlider,那麼就可以確保選擇的是指定範圍內的數字。

在 Swing 中,JSlider 看起來如下所示:

JSlider

JSlider 中的重要方法是:

  • get/setMinimum()獲取/設定可以選擇的最小值。
  • get/setMaximum()獲取/設定可以選擇的最大值。
  • get/setOrientation()獲取/設定 JSlider 是上/下還是左/右滾動條。
  • get/setValue()獲取/設定 JSlider 的初始值。

 JSlider

與 JSlider 非常像,可以用 JSpinner 允許使用者選擇一個整數值。JSlider 的一個主要優勢就是比 JSlider 的空間緊湊。但是,它的不足就是無法方便地設定其邊界。

但是,兩個元件之間的比較僅此而已。JSpinner 更加靈活,可以用來在任意組的值之間進行選擇。除了在數字間選擇,它還可以用來在日期、名稱、顏色和任何事之間進行選擇。這使 JSpinner 極為強大,允許您提供其中只包含預定義的選擇的元件。使用這種方式,它與 JComboBox 類似,但是它們的應用不能互換。只應把 JSpinner 用在邏輯上連續的選擇 —— 數字和日期是最合邏輯的選擇。而另一方面,在呈現看起來隨機的選擇並且選擇之間沒有連線的時候,JComboBox 是更好的選擇。

JSpinner 看起來如下所示:

JSpinner

重要方法是:

  • get/setValue()獲取/設定 JSpinner 的初始值,在基本例項中,需要是整數。
  • getNextValue()獲取按下上箭頭按鈕之後應當選中的下一個值。
  • getPreviousValue()獲取按下下箭頭按鈕之後應當選中的前一個值。

 JToolBar

JToolBar 充當其他元件(JButton、JComboBoxe 等)的調色盤,共同構成您在大多數應用程式中熟悉的工具欄。工具欄允許程式把常用的命令放在可以迅速發現的位置,並把它們以常用命令組的形式組合在一起。一般(但不總是這樣)情況下,工具欄按鈕在選單欄中會有對應的命令。雖然這不是必需的,但已經變成了一種公共實踐,您也應當試著這麼做。

JToolBar 也提供了您在其他工具欄中看到過的其他功能:“浮動”的能力(也就是成為主幀頂部獨立的幀)。

下圖顯示了一個非浮動 JToolBar:

非浮動 JToolBar

對於 JToolBar,要記住的重要方法是:is/setFloatable(),它獲取/設定 JToolBar 是否可以浮動。

 JToolTip

您可能到處都看到過 JToolTip,但是從來不知道它們叫什麼。它們就像您鞋帶上的塑料部件 —— 到處都有,但是您就是不知道它們正確的名字(如果您想知道,那麼可以叫它們 金屬箍)。JToolTip 就是您將滑鼠停留在某個東西上面的時候彈出來的小“泡泡”。它們在應用程式中可能非常有用,可以為難用的專案提供幫助、擴充套件資訊,甚至在擁擠的 UI 中顯示某個專案的完整文字。在 Swing 中,可以通過把滑鼠放在某個元件上的特定時間來觸發它們;它們通常在滑鼠處於不活動狀態大約 1 秒鐘之後顯示。只要滑鼠還停留在那個元件上,它們就保持可見。

JToolTip 的重要部分是它的易用性。setToolTip() 方法是 JComponent 類中的一個方法,這意味著每個 Swing 元件都能有一個與之關聯的工具提示。雖然 JToolTip 本身也是一個 Swing 類,但目前,對於您的需要,它確實沒有提供更多功能,而且本身也不該被建立。可以通過呼叫 JComponent 的 setToolTip() 函式訪問和使用它。

以下是 JToolTip 看起來的樣子:

A JToolTip



附加的swing小部件(下)

JOptionPane

JOptionPane 是在 Swing 中類似“快捷方式”的東西。通常,作為 UI 開發人員,您需要向用戶呈現快速資訊,讓使用者瞭解錯誤和資訊。甚至可能想得到一些快速資料,例如名稱或數字。在 Swing 中,JOptionPane 類為這些東西提供了快捷方式,但這並不是它必須完成的任務。不需要讓每個開發人員重頭開始重複相同的工作,Swing 已經提供了這個基本的但很有用的類,為 UI 開發人員提供了獲取和接收簡單訊息的簡易方法。

以下是一個 JOptionPane:

JOptionPane

使用 JOptionPane 時有點麻煩的是可以使用的全部選項。雖然簡單,但是它仍然提供了大量選項,這些選項有可能造成混淆。學習 JOptionPane 的最好方法就是使用它;編寫程式碼,觀察彈出的是什麼。這個元件幾乎可以讓您修改它的每一方面:幀標題、訊息本身、顯示的圖示、按鈕選項,以及是否需要文字響應。因為有太多的可能性,無法在本教程中一一列舉它們,所以您最好是訪問 JOptionPane 的 API 頁面,檢視它的眾多可能性。

 JTextArea

JTextArea 比 JTextField 更進了一步。JTextField 被侷限在一行文字中,而 JTextArea 擴充套件了這個能力,支援多行文字。可以把它想像成一個空白頁,您可以在其中的任意地方進行輸入。正如您可能猜到的,JTextArea 包含許多與 JTextField 相同的功能,畢竟,它們實際上是相同的元件。但是 JTextArea 提供了一些額外的重要功能,可以把它區別開。這些功能包括單詞自動換行的能力(即把長文字自動換行到下一行,而不是將單詞從中斷開)、對文字自動換行的能力(即把長的文字行移動到下一行,而不是建立一個需要水平滾動條的非常長的行)。

Swing 中的 JTextArea 看起來就像您期望的那樣:

A JTextArea

支援行和單詞的自動換行的重要方法是:

  • is/setLineWrap()設定在行過長的時候是否要自動換行。
  • is/setWrapStyleWord()設定在單詞過長的時候是否要把長單詞移到下一行。

 JScrollPane

上面的示例構造完成之後,假設 JTextArea 包含太多文字,而給定的空間中容納不下,那這該怎麼辦?如果您以為會自動出現滾動條,那麼很不幸,您錯了。JScrollPane 添補了這個空白,為 Swing 元件提供了處理所有與滾動條相關的動作。所以雖然為每個需要的元件提供滾動塊可能有些痛苦,但是一旦添加了它,它就會自動處理每件事,包括在需要的時候隱藏/顯示滾動條。

除了用需要自動換行的元件建立 JScrollPane 之外,不必直接處理它。根據上面的示例,用 JTextArea 呼叫 JScrollPane 的建構函式,這為 JTextArea 建立了在文字過長時滾動的能力:

 JScrollPane scroll = new JScrollPane(getTextArea()); add(scroll); 

更新後的示例看起來如下所示:

JScrollPane 示例

JScrollPane 也公開了它將建立的兩個 JScrollBar。這些 JScrollBar 元件也包含一些方法,可以用這些方法來修改元件的行為(雖然它們不在本教程的範圍之內)。

使用 JScrollPane 需要的方法是:

  • getHorizontalScrollBar()返回水平的 JScrollBar 元件。
  • getVerticalScrollBar():返回垂直的 JScrollBar 元件.
  • get/setHorizontalScrollBarPolicy()這個“策略”可以是以下三個之一:Always、Never 或 As Needed。
  • get/setVerticalScrollBarPolicy()與水平函式相同。

JList

JList 是一個有用的元件,用於向用戶呈現許多選擇。可以把它當作 JComboBox 的擴充套件。JList 提供了更多選擇,並添加了多選的能力。在 JList 與 JComboBox 之間進行選擇通常取決於以下兩個特性:如果需要多選,或者選擇的選項超過 15 個(雖然這個數字並不是通用規則),那麼就應當選擇 JList。

應用將 JList 與 JScrollPane 結合使用,就像上面演示的那樣,因為它能夠呈現比它的空間所能容納的更多的選項。

JList 包含選擇模型的概念(在 JTable 中也會看到),在這裡,可以設定 JList 接受不同型別的選擇。這些型別是:單一選擇(只能選擇一項)、單一間隔選擇(只能選擇相鄰選項),以及任意多項或者多項間隔選擇(可以選擇任意數量、任意組合的選擇)。

JList 是第一個我稱為 “複雜元件” 的元件,該複雜元件還包含 JTable 和 JTree,它們支援大量的定製變化,其中包括改變 UI 的表現方式、處理資料的方式。因為本教程只是想介紹基礎知識,所以我不想深入這些更高階的功能,但是在使用這些元件時有件事需要記住 —— 它們帶來的挑戰要比目前為止介紹過的所有元件都大。

JList 在 Swing 中看起來如下所示:

JList

JList 中有許多處理資料的函式,而且根據我的說法,這些也只不過是使用 JList 的細節的皮毛而已。以下是一些基本方法:

  • get/setSelectedIndex()獲取/設定列表中選中的行;在多選擇列表的情況下,返回一個 int[]
  • get/setSelectionMode()與上面解釋的一樣,獲取/設定選擇模式,模式有:單一、單一間隔和多選間隔。
  • setListData()設定在 JList 中使用的資料。
  • get/setSelectedValue()獲得選中的物件(與選中行號對應)。

 JTable

在考慮 JTable 時,請想像一下一個 Excel 工作表,這樣就可以對 JTable 在 Swing 中的作用有一個清晰的印象。它與工作表共享許多相同的特徵:單元格、行、列、移動列、隱藏列等。JTable 把 JList 的想法更進了一步。它不是在一列中顯示資料,而是在多列中顯示資料。讓我們以人為例。JList 只能顯示人的一個屬性 —— 例如他或她的名字。而 JTable 就能夠顯示多個屬性 —— 名字、年齡、地址,等等。JTable 是支援提供資料的大多數資訊的 Swing 元件。

不幸的是,作為代價,JTable 也是最難對付的 Swing 元件。許多 UI 開發人員都為了學習 JTable 的每個細節而頭痛。在這裡,我希望我把能把您解救出來,只用您的 JTable 知識處理問題。

許多 JList 中的概念也擴充套件到了 JTable,其中包括不同的選擇間隔的概念。但是 JList 中一列的概念變成了 JTable 的單元格的概念。這意味著在 JTable 中進行選擇時會有不同的方式,例如列、行或者一個單元格。

在 Swing 中,JTable 看起來如下所示:

JTable

最後,JTable 的大多數函式都超出本教程的範圍;“中級 Swing”會深入這個複雜元件的更多細節。

 JTree

JTree 是另外一個複雜元件,它不像 JTable 那樣難用,但是也不像 JList 那麼容易。使用 JTree 時麻煩的部分是它要求的資料模型。

JTree 的功能來自樹的概念,樹有分支和葉子。您在 Windows 中使用 IE 瀏覽器時,可能非常熟悉這個概念 —— 可以展開和摺疊分支,顯示可以選擇和取消選擇的不同葉子。

您很有可能發現樹在應用程式中不像表格或列表那樣有用,所以在 Internet 上沒有許多有幫助的這方面的示例。實際上,像 JTable 一樣,JTree 沒有什麼入門級的功能。如果決定使用 JTree,那麼立即就可以達到中級水平,當然還必須學習隨之而來的概念。因此,示例應用程式沒有介紹 JTree,所以也很不幸,不管是入門教程還是中級教程,都沒有涉及這個不太流行的元件。

但是,樹有一些時候是符合需求的合理的 UI 元件。檔案/目錄系統就是一個示例(就像在 IE 瀏覽器中那樣),而且當資料採取層次結構的時候,也就是說資料採用樹的形式的時候,JTree 就是最佳元件。

在 Swing 中,JTree 看起來如下所示:

JTree



Swing概念

佈局、模型和事件

既然您已經知道了大多數(肯定不是全部)可以用來製作 UI 的元件,那麼就必須實際用它們做些什麼。您不能只是隨意地把它們放在螢幕上,然後就指望它們立即就能工作。您必須把它們放在特定的點上,對它們的互動作出反應,然後根據互動更新它們,用資料填充它們。要填滿 UI 知識的這片空白,還需要更多地學習 UI 的其他重要部分。

所以,讓我們來研究以下內容:

  • 佈局:Swing 包括許多佈局,佈局也是類,負責處理元件在應用程式中的擺放位置,以及在應用程式改變尺寸或者刪除、新增元件時對元件進行相應處理。
  • 事件:您需要對按下按鈕、單擊滑鼠和使用者在 UI 上能做的每件事進行響應。想像一下,如果不能響應會發生什麼 —— 使用者單擊之後,什麼變化也沒有。
  • 模型: 對於更高階的元件(列表、表格和樹),以及一些像 JComboBox 這樣的更容易的元件來說,模型是處理資料最有效的途徑。它們把大部分處理資料的工作從實際的元件本身撤出來(請回想一下前面討論的 MVC),並提供了一個公共資料物件類(例如 VectorArrayList)的包裝器。

簡單佈局

就像在前面提到過的,佈局替您處理元件在應用程式中的擺放。您的第一個問題可能是“為什麼不能用畫素告訴它應當在什麼地方呢?”是的,您可以這樣做,但是在視窗改變大小的時候,或者更糟一些情況,即使用者改變其螢幕的解析度的時候,亦或在有人想在其他作業系統上試用應用程式的時候,您立刻就會遇到麻煩。佈局管理器把這些擔心一掃而空。不是每個人都用相同的設定,所以佈局管理器會建立“相對”佈局,允許您指定元件相對於其他元件的擺放方式,決定事物改變尺寸的方式。這是好的部分:比聽起來更容易。只要呼叫 setLayout(yourLayout) 設定佈局管理器即可。後面對 add() 的呼叫可以將元件新增到容器中,並讓佈局管理器負責將它放在應當的位置上。

目前在 Swing 中包含了大量佈局;看起來好象每次釋出都會有一個新佈局負責不同的目的。但是,有些經過實踐檢驗的佈局一直存在,而且會永遠存在,我指的是永遠 —— 因為從 1995 年 Java 語言的第一個發行版開始,就有這些佈局。這些佈局是:FlowLayout、GridLayout 和 BorderLayout。

FlowLayout 從左到右安排元件。當空間不足時,就移到下一行。它是使用起來最簡單的佈局,因此,也就是能力最弱的佈局:

 setLayout(new FlowLayout()); add(new JButton("Button1")); add(new JButton("Button2")); add(new JButton("Button3")); 

FlowLayout 例項

GridLayout 就像您想像的那樣工作:它允許指定行和列的數量,然後在新增元件時把元件放在這些單元格中:

 setLayout(new GridLayout(1,2)); add(new JButton("Button1")); add(new JButton("Button2")); add(new JButton("Button3")); 

GridLayout 例項

即使 Swing 中添加了許多新的佈局管理器,BorderLayout 仍然是其中非常有用的一個。即使有經驗的 UI 開發人員也經常使用 BorderLayout。它使用東、南、西、北、中的概念在螢幕上放置元件:

 setLayout(new BorderLayout()); add(new JButton("Button1"), "North"); add(new JButton("Button2"), "Center"); add(new JButton("Button3"), "West"); 

BorderLayout 例項

 GridBagLayout

雖然上面的示例對於簡單的佈局來說很好,但是更高階的 UI 需要更高階的佈局管理器。這是 GridBagLayout 發揮作用的地方。不幸的是,使用它的時候極易混淆、極為困難,每個曾經用過它的人都會同意這點。我也不能反對;但是除了它的困難之外,它可能是用 Swing 內建的佈局管理器建立漂亮 UI 的最好方式。

以下是我的第一個小建議:在最新版的 Eclipse 中,有內建的視覺化構建器,這個個小建議可以自動根據每個螢幕的需要來構建必需的 GridBagLayout 程式碼。請使用這個功能!它會節約無數為了讓數字正確而浪費的時間。所以在我用這一節解釋 GridBagLayout 如何工作、如何調整它才能讓它做得最好時,建議您去找一個視覺化構建器並生成程式碼。它會節約您的工作時間

事件

最後,我們來到 Swing 最重要的一部分:處理事件,對 UI 的互動作出反應。Swing 用事件/偵聽器模型處理事件。這個模型的工作方式是:允許某個類登記到某個元件的某個事件上。登記到事件的這個類叫做偵聽器,因為它等候元件的事件發生,而且在事件發生時採取行動。元件本身知道如何“啟用”事件(即,知道它能生成的互動型別,以及如何讓偵聽器知道這個互動什麼時候發生)。元件與包含有關互動資訊的事件和類針對互動進行通訊。

把技術方面的空談放在一邊,我們來看幾個 Swing 中事件的例項。首先從最簡單的示例開始,即一個 JButton,按下它的時候,會在控制檯上輸出“Hello”。

JButton 知道它什麼時候被按下;這是在內部處理的,不需要程式碼處理它。但是,偵聽器需要進行登記,以接收來自 JButton 的事件,這樣您才能輸出“Hello”。listener 類通過實現 listener 介面然後呼叫 JButton 上的 addActionListener() 做到這一點:

 // Create the JButton JButton b = new JButton("Button"); // Register as a listener b.addActionListener(new HelloListener()); class HelloListener implements ActionListener { // The interface method to receive button clicks public void actionPerformed(ActionEvent e) { System.out.println("Hello"); } } 

JList 也用類似的方式工作。當有人在 JList 中選中什麼時,您可能想把選中的物件輸出到控制檯上:

 // myList is a JList populate with data myList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { Object o = myList.getSelectedItem(); System.out.println(o.toString()); } } ); 

從這兩個示例,您應當能夠理解事件/偵聽器模型在 Swing 中如何工作了。實際上,Swing 中的每個互動都是以這種方式處理的,所以通過理解這個模型,您就立即能夠理解在 Swing 中如何處理每個事件,以及如何對使用者可能拋給您的任何互動做反應了。

模型

現在,您應當瞭解了 Java 的集合(Collection),這是一組處理資料的 Java 類。這些類包括 ArrayListHashMapSet。大多數應用程式在反覆處理資料時,經常用這些類。但是,當需要在 UI 中使用這些資料類時,出現了一個限制。UI 不知道如何顯示它們。請先想一分鐘。如果有一個 JList 和一個某種資料物件(例如 Person 物件)的 ArrayListJList 怎樣才能知道要顯示什麼?它是要顯示某個人的名字,還是連名帶姓一起顯示?

這就是模型的概念發揮作用的地方了。雖然模型這個術語表達的範圍更大,但是在本教程的示例中,我用 UI 模型這個術語描述元件用來顯示資料的類。

在 Swing 中每個處理集合資料的的元件都採用模型的概念,而且這也是使用和操縱資料的首選方法。它清晰地把 UI 的工作與底層資料分開(請回想 MVC 示例)。模型工作的機制是向元件描述如何顯示集合資料。我說的“描述”指的是什麼呢?每個元件需要的描述略有不同:

  • JComboBox 要求其模型告訴它把什麼文字作為選項顯示,以及有多少選項。
  • JSpinner 要求其模型告訴它顯示什麼文字,前一個和下一個選擇是什麼。
  • JList 也要求其模型告訴它把什麼文字作為選項顯示,存在多少選項。
  • JTable 要求的更多:它要求模型告訴它存在多少列和多少行,列名稱、每列的類以及在每個單元格中顯示什麼文字。
  • JTree 要求它的模型告訴它整個樹的根節點、父節點和子節點。

您可能會問:為什麼要做這麼些工作?為什麼要把這些功能分開?請想像以下場景:您有一個複雜的 JTable,有許多列資料,您在許多不同的螢幕上使用這個表格。如果您突然決定刪除某個列,那麼怎麼做會更容易呢?修改您使用的每個 JTable 例項中的程式碼?還是建立一個可以在每個 JTable 例項中使用的模型類,然後只修改這一個模型類呢?顯然,所做的修改越少越好。

模型示例

我們來看看模型如何工作,在一個簡單的 JComboBox 示例中使用模型。在 JComboBox 前面的演示中,我介紹瞭如何呼叫 setItem() 向資料中新增專案。雖然對於簡單的演示,這樣做可以接受,但是在實際的應用程式中很少這麼用。畢竟,在有 25 個選項,而且選項不斷變化的時候,您還真的想每次都呼叫 addItem() 25 次對這些選項進行迭代嗎?當然不是。

JComboBox 包含一個方法呼叫 setModel(),它接受 ComboBoxModel 類的例項。應當用這個方法代替 addItem() 方法來建立 JComboBox 中的資料。