1. 程式人生 > >Java核心(Swing 程式設計4-列表元件、文字元件、常用時間監聽器)

Java核心(Swing 程式設計4-列表元件、文字元件、常用時間監聽器)

一、列表元件

    Swing 中提供了兩種列表元件,分別為下拉列表框與列表框。下拉列表框與列表框都是帶有一系列專案的元件,使用者可以從中選擇需要的專案。列表框較下拉列表框更直觀,它將所有的專案羅列在列表框中;但下拉列表框較列表框更為便捷、美觀,它將所有的專案隱藏起來,當用戶選用其中的專案時才會顯現出來。

    1.1 下拉列表框元件

    1.1.1  JComboBox 類

    下拉列表框是一個帶條狀的顯示區,它具有下拉功能,在下拉列表框的右方存在一個倒三角形的按鈕,當用戶單擊該按鈕時,下拉 列表框中的專案將會以列表形式顯示出來。

    Swing 中的下拉列表框使用 JComboBox 類物件來表示,它是 javax.swing.JComponent 類的子類。它的常用構造方法如下 : 

    ( 1 ) :public JComboBox() 。

    ( 2 ) :public JComboBox(ComboBoxModel dataModel) 。

    ( 3 ) :public JComboBox(Objet[] arrayDate) 。

    ( 4 ) :public JComboBox(Vector vector) 。

    在初始化下拉列表框時,可以選擇同時指定下拉列表框中的專案內容,也可以在程式中使用其他方法設定下拉列表框中的內容,下拉列表框中的內容可以被封裝在 ComboBoxModel 型別、陣列或 Vector 型別中。

    1.1.2  JComboBox 模型

    在開發過程中,一般將下拉列表框中的專案封裝為 ComboBoxModel 的情況比較多。 ComboBoxModel 為介面,它代表一般模型,可以自定義一個類實現該介面,然後再初始化 JComboBox 物件時向上轉型為 ComboBoxModel 介面型別,但是必須實現以下兩種方法 :

    ( 1 ) :public void setSelectedIten(Object item) 。

    ( 2 ) :public Object getSelectedItem() 。

    其中,setSelectedItem() 方法用於設定下拉列表框中的選中項, getSelectedItem() 方法用於返回下拉列表框中的選中項,有了這兩個方法,就可以輕鬆地對下拉列表框中的專案進行操作。

    自定義這個類除了實現該介面之外,還可以繼承 AbstractListModel 類,在該類中也有兩個操作下拉列表框的重要方法 :

    ( 1 ) : getSize()  :返回列表的長度 。

    ( 2 ) : getElementAt(int index)  :返回指定索引處的值 。

    eg 1.1.2 在專案中建立 JComboBoxModelTest 類,使該類繼承 JFrame 類稱為窗體元件,在類中建立下拉列表框,並新增到窗體中。

package com.SwingDemo;

import java.awt.*;
import javax.swing.*;

public class JComboBoxModelTest extends JFrame {
    private static final long serialVersionUID = 1L;
    JComboBox<String> jBox = new JComboBox<>(new MyComboBox());
    JLabel jLabel = new JLabel("請選擇證件:");
    public JComboBoxModelTest() {
        setSize(new Dimension(160, 180));
        setVisible(true);
        setTitle("在視窗中設定下拉列表框");
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        Container container = getContentPane();
        container.setLayout(new FlowLayout());
        container.add(jBox);
        container.add(jLabel);
    }

    public static void main(String[] args) {
        new JComboBoxModelTest();
    }
}

class MyComboBox extends AbstractListModel<String> implements ComboBoxModel<String> {
    private static final long serialVersionUID = 1L;
    String selectedItem = null;
    String[] teStrings = { "身份證", "軍人證", "學生證", "工作證" };
    @Override
    public String getElementAt(int index) {        //根據索引返回值
        return teStrings[index];
    }
    @Override
    public int getSize() {        //返回下拉列表框專案的數目
        return teStrings.length;
    }
    @Override
    public void setSelectedItem(Object anItem) {        //設定下拉列表框專案
        selectedItem = (String) selectedItem;
    }
    @Override
    public Object getSelectedItem() {        //獲取下拉列表框專案
        return selectedItem;
    }
    public int getIndex() { 
        for (int i = 0; i < teStrings.length; i++) {
            if (teStrings[i].equals(getSelectedItem())) {
                return i;
            }
        }
        return 0;
    }
}
    執行結果為 :

        

    自定義了一個實現 ComboBoxModel 介面並繼承 AbstractListModel 類的類,這樣這個類就可以實現或重寫該介面與該類中的重要方法,同時在定義下拉列表框時,只要將該類向上轉型為 ComboBoxModel 介面即可。

    1.2 列表框元件

    列表框(JList)與下拉列表框的區別不僅表現在外觀上,當啟用下拉列表框時,還會出現下拉列表框中的內容;但列表框只是在窗體上佔據固定的大小,如果需要列表框具有滾動效果,可以將列表框放入滾動面板中。使用者在選擇列表框中的某一項時,按住 Shift 鍵並選擇列表框中的其他專案,則當前選項和其他專案之間的選項將全部被選中;也可以按住 Ctrl 鍵並單擊列表框中的單個專案,這樣可以是列表框中被單擊的專案反覆切換非選擇狀態或選擇狀態。

    Swing 中使用 JList 類物件來表示列表框,常用的構造方法 :

    ( 1 ) :public void JList() 。

    ( 2 ) :public void JList(Object[] listData) 。

    ( 3 ) :public void JList(Vector listData) 。

    ( 4 ) :public void JList(ListModel dataModel) 。

    在上述構造方法中,存在一個沒有引數的構造方法,可以通過在初始化列表框後使用 setListData() 方法對列表框進行設定,也可以在初始化的過程中對列表框中的專案進行設定。設定的方式有3 中型別,包括陣列、Vector 型別和 ListModel 型別。

    當使用陣列作為構造方法的引數時,首先需要建立列表專案的數字,然後再利用構造方法來初始化列表框。

    eg 1.2-1 使用陣列作為初始化列表框的引數 。

String[] contents = {"列表 1","列表 2","列表 3","列表 4"};
JList jlist = new JList(contents);
   eg 1.2-2 如果使用上述構造方法中的第 3 個構造方法,將 Vector 型別的資料作為初始化 JList 元件的引數。
Vector vector = new Vector();
JList jlist = new JList(vector);
vector.add("列表 1");
vector.add("列表 2");
vector.add("列表 3");
vector.add("列表 4");

    如果使用 ListModel 模型為引數,需要建立 ListModel 物件。ListModel 是 Swing 包中的一個介面,它提供了獲取列表框屬性的方法。但是在通常情況下,為了使使用者不完全實現 ListModel 介面中的方法,通常自定義一個類繼承實現該介面的抽象類 AbstractListModel 。在這個類中提供了 getElementAt() 與 getSize() 方法,其中 getElementAt() 方法代表根據專案的索引獲取列表框中的值,而 getSize() 方法用於獲取列表框中的專案個數。

    eg 1.2-3 在專案中建立 JListTest 類,是該類繼承 JFrame 類成為窗體元件,在該類中建立列表框,並新增到窗體中。

package com.SwingDemo;

import java.awt.*;
import javax.swing.*;

public class JListTest extends JFrame {
    private static final long serialVersionUID = 1L;
    public JListTest() {
        Container container = getContentPane();
        container.setLayout(null);
        JList<String> jList = new JList<>(new MyListModel());
        JScrollPane jScrollPane = new JScrollPane(jList);
        jScrollPane.setBounds(10, 10, 100, 100);
        container.add(jList);
        setTitle("在這個窗體使用了列表框");
        setVisible(true);
        setSize(200, 150);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

    public static void main(String[] args) {
        new JListTest();
    }
}

class MyListModel extends AbstractListModel<String> {        // 繼承抽象類 AbstractListModel
    private static final long serialVersionUID = 1L;
    // 設定列表框內容
    private String[] contents = { "列表 1", "列表 2", "列表 3", "列表 4", "列表 5", "列表 6" };
    @Override
    public String getElementAt(int index) {        // 重寫 getElementAt() 方法
        if (index < contents.length) {
            return contents[index++];
        } else {
            return null;
        }
    }
    @Override
    public int getSize() {        // 重寫 getSize() 方法
        return contents.length;
    }
}

    執行結果為 :

        

    還可以使用 DefaultListModel 類建立列表框,該類擴充套件了 AbstractListModel 類,所以也可以通過 DefaultListModel  物件向上轉型為 ListModel 介面初始化列表框,同時 DefaultListModel  類提供了 dModel.addElement() 方法實現將內容新增至列表框中。

    eg 1.2-4 使用 DefaultListModel 類建立列表框 。

final String[] flavors = { "列表1", "列表2", "列表3", "列表4", "列表5", "列表6" };
final DefaultListModel<String> dModel = new DefaultListModel<String>();
final JList<String> jList = new JList<>(dModel);        //例項化 JList 物件
for(int i=0;i<4;i++) {
    dModel.addElement(flavors[i]);        //為模型新增內容
}

二、文字元件

    文字元件在實際專案開發中使用最為廣泛,尤其是文字框與密碼框元件,通過文字元件可以很輕鬆地處理單行文字、多行文字、口令欄位 。

    2.1 文字框元件

    文字框(JTextField)用來顯示或編輯一個單行文字,在 Swing 中通過 javax.swing.JTextField 類物件建立,該類繼承了 javax.swing.text.JTextComponent 類。

    文字框常用的構造方法 :

    ( 1 )  :public JTextField() 。

    ( 2 )  :public JTextField(String text) 。

    ( 3 )  :public JTextField(int fieldwidth) 。 

    ( 4 )  :public JTextField(String text , int fieldwidth) 。

    ( 5 )  :public JTextField(Document docModel , String text , int fieldWidth) 。

    可以通過在初始化文字框時設定文字框的預設文字、文字框的長度等實現。

    eg 2.1 在專案中建立 JTextFieldTest 類,使該類繼承 JFrame 類成為窗體元件,在該類中建立文字框和按鈕元件,並新增到窗體中。    

package com.SwingDemo;

import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

public class JTextFieldTest extends JFrame {
    private static final long serialVersionUID = 1L;
    public JTextFieldTest() {
        setSize(250, 100);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        Container container = getContentPane();
        getContentPane().setLayout(new FlowLayout());
        final JTextField jTextField = new JTextField("aaa", 20);
        final JButton jButton = new JButton("清除");
        container.add(jTextField);
        container.add(jButton);
        jTextField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                jTextField.setText("觸發事件");
            }
        });
        jButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                jTextField.setText("");
                jTextField.requestFocus();
            }
        });
        setVisible(true);
    }
    public static void main(String[] args) {
        new JTextFieldTest();
    }
}

    執行結果為 :

                在例子中主要設定了一個文字框和一個按鈕,然後分別為文字框和按鈕設定事件,當用戶將游標焦點落於文字框中並按下 Enter 鍵時,文字框將執行 actionPerformed() 方法中設定的操作。同時還為按鈕添加了相應的時間,當用戶單擊“清除”按鈕時,文字框中的字串將被清除 。

    2.2 密碼框元件

    密碼框(JPasswordField)與文字框的定義與用法基本相同,唯一不同的是密碼框將使用者輸入的字串以某種符號進行加密。密碼框物件是通過 javax.swing.JPasswordField 類來建立的,JPasswordField 類的構造方法與 JTextField 類的構造方法非常相似。

    ( 1 )  :public JPasswordField() 。

    ( 2 )  :public JPasswordField(String text) 。

    ( 3 )  :public JPasswordField(int fieldwidth) 。 

    ( 4 )  :public JPasswordField(String text , int fieldwidth) 。

    ( 5 )  :public JPasswordField(Document docModel , String text , int fieldWidth) 。

    eg 2.2  定義密碼框 。

JPasswordField jp = new JPasswordField();
jp.setEchoChar('#');//設定回顯字元

     在 JPasswordField 類中提供一個 setEchoChar() 方法,可以改變密碼框的回顯字元 。

    2.3 文字域元件

    Swing 中任何一個文字區域都是 JTextArea 型別的物件。JTextArea 常用的構造方法如下 :

    ( 1 )  :public JTextArea () 。

    ( 2 )  :public JTextArea (String text) 。

    ( 3 )  :public JTextArea (int rows , int columns) 。 

    ( 4 )  :public JTextArea (Document doc) 。

    ( 5 )  :public JTextArea (Document doc, String text , int rows , int columns) 。

    可以在初始化文字域時提供預設文字以及文字域的長與寬 。

    eg 2.3  在專案中建立 JTextAreaTest 類,使該類繼承 JFrame 類成為窗體元件,在該類中建立 JTextArea 元件的例項,並新增到窗體中 。

package com.SwingDemo;

import java.awt.*;
import javax.swing.*;

public class JTextAreaTest extends JFrame {
    private static final long serialVersionUID = 1L;

    public JTextAreaTest() {
        setSize(200, 100);
        setTitle("定義自動換行的文字域");
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        Container container = getContentPane();
        JTextArea jArea = new JTextArea("文字域", 6, 6);
        jArea.setLineWrap(true);        // 可以自動換行
        container.add(jArea);
        setVisible(true);
    }

    public static void main(String[] args) {
        new JTextAreaTest();
    }
}

    執行結果為 :

    

    JTextArea 類中存在一個 setLineWrap()  方法,該方法用於設定文字域是否可以自動換行,如果將該方法的引數設定為 true ,文字域將自動換行,否則則不自動換行 。

三 、常用事件監聽器    

    之前所講的元件本身並不帶有任何功能。例如,在窗體中定義一個按鈕,當用戶單擊該按鈕時,雖然按鈕可以凹凸顯示,但在窗體中並沒有實現任何功能。這是需要為按鈕新增特定事件監聽器,該監聽器負責處理使用者單擊按鈕後實現的功能。

    3.1 監聽事件簡介

    在 Swing 事件模型中由 3 個分離的物件完成對事件的處理,分別為事件源、事件以及監聽程式。事件源觸發一個事件,它被一個或多個“監聽器”接收,監聽器負責處理事件。

    所謂事件監聽器,實質上就是一個“實現特定型別監聽器介面”的類物件。具體地說,事件幾乎都以物件來表示,它是某種事件類的物件,事件源(如按鈕)會在使用者作出相應的動作(如按鈕被按下)時產生事件物件,如動作事件對應 ActionEvent 類物件,同時要編寫一個監聽器的類必須實現相應的介面,如 ActionEvent  類對應的是 ActionListener 介面,需要獲取某個事件物件就必須實現相應的介面,同時需要將介面中的方法一一實現。最後事件源(按鈕)呼叫相應的方法載入這個“實現特定型別監聽器介面”的類物件,所有的事件源都具有 addXXXListener() 和 removeXXXListener() 方法(其中 XXX 方法表示監聽事件型別),這樣就可以為元件新增或移除相應的事件監聽器 。

    3.2 動作事件監聽器 

    動作事件(ActionEvent)監聽器是 Swing 中比較常用的事件監聽器,很多元件的動作都會使用它監聽,如按鈕被單擊。

表 3.2 動作事件監聽器
事件名稱事件源監聽介面新增或刪除相應型別監聽器的方法
ActionEventJButton 、 JList 、 JTextField 等ActionListenteraddActionListener() 、removeActionListener()

    eg 3.2 在專案中建立 SimpleEvent 類,使該類繼承 JFrame 類成為窗體元件,在類中建立按鈕元件,為按鈕元件新增動作監聽器,然後將按鈕元件新增到窗體中。

package com.SwingDemo;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class SimpleEvent extends JFrame {
    private static final long serialVersionUID = 1L;
    private JButton jb = new JButton("我是按鈕,單擊我");
    public SimpleEvent() {
        setLayout(null);
        setSize(200, 100);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        Container container = getContentPane();
        container.add(jb);
        jb.setBounds(10, 10, 100, 30);
        jb.addActionListener(new jbAction());
        setVisible(true);
    }

    class jbAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            jb.setText("我被單擊了");
        }
    }

    public static void main(String[] args) {
        new SimpleEvent();
    }
}

    執行結果為 : 

        

    在例子中,為按鈕設定了動作監聽器。由於獲取時間監聽時需要獲取實現 ActionListener 介面的物件,所以定義了一個內部類 jbAction 實現 ActionListener 介面,同時在該內部類中實現了 actionPerformed() 方法,也就是在 actionPerformed() 方法中定義當用戶單擊該按鈕後實現怎樣的功能。

    3.3 焦點時間監聽器

    焦點事件(FocusEvent)監聽器在實際專案開發中應用也比較廣泛,如將游標焦點離開一個文字框時需要彈出一個對話方塊,或者將焦點返回給該文字框等。

表 3.3 焦點事件監聽器
事件名稱事件源監聽介面新增或刪除相應型別監聽器的方法
FocusEvetnComponent 以及派生類FocusListeneraddFocusListener() 、removeFocusListener()

    eg 3.3 在專案中建立 FocusEventTest 類,使該類繼承 JFrame 類成為窗體元件,在類中建立文字框元件,併為文字框新增焦點事件監聽器,將文字框元件新增到窗體中。

package com.SwingDemo;

import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

public class FocusEventTest extends JFrame {
    private static final long serialVersionUID = 1L;

    public FocusEventTest() {
        setSize(250, 100);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        Container container = getContentPane();
        container.setLayout(new FlowLayout());
        final JLabel jLabel = new JLabel();
        container.add(jLabel);
        JTextField jTextField1 = new JTextField("請單擊其他文字框", 10);
        JTextField jTextField2 = new JTextField("請單擊我", 10);
        container.add(jTextField1);
        container.add(jTextField2);
        jTextField1.addFocusListener(new FocusListener() {
            // 元件失去焦點時呼叫的方法
            @Override
            public void focusLost(FocusEvent e) {
                JOptionPane.showMessageDialog(null, "文字框失去焦點");
            }

            // 元件獲取鍵盤焦點時呼叫的方法
            @Override
            public void focusGained(FocusEvent e) {

            }
        });
        setVisible(true);
    }

    public static void main(String[] args) {
        new FocusEventTest();
    }
}

    執行結果為 :

    

    在例子中,為文字框元件添加了焦點事件監聽器。這個監聽器需要實現 FocusListener 介面。在該介面中定義了兩個方法,分別為 focusLost() 與 focusGained() 方法,其中 focusLost() 方法是在元件失去焦點時呼叫的,而  focusGained() 方法是在元件獲取焦點呼叫的。本例需要實現在文字框失去焦點時彈出相應對話方塊的功能,所以重寫 focusLost() 方法,同時在為文字框新增監聽時使用了匿名內部類的形式,將實現 FocusListener 介面物件傳遞給 addFocusListener() 方法。