Java 入門指南 - 事件處理

我們要處理 GUI 中的事件 (event) ,首先得讓視窗元件傾聽所有使用者可能的動作,依據使用者的動作,例如在文字方塊 (textfield) 中輸入文字,我們設計程式相對應的動作,如可以在另一個標籤 (label) 中顯示提示訊息等




因此,我們得要在 EncryptorGUI 中實作 (implement) 傾聽者介面,然後實作出相對應的方法,最後視窗元件得登記它要傾聽事件。如上述,我們將 Input 標籤後的文字方塊設計成只要使用者輸入任何字元, hint... 標籤就隨之顯示相同的文字,程式如下
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;

public class EncryptorGUI implements ActionListener, CaretListener {
    private JFrame frame;
    private String[] name;
    private int att[][];
    private ArrayList<JComponent> GUIComponent;
    private String userinput;
    
    public EncryptorGUI() {
        int fill[]  =  { GridBagConstraints.BOTH,
                         GridBagConstraints.VERTICAL,
                         GridBagConstraints.HORIZONTAL,
                         GridBagConstraints.NONE};
        int anchor[] = { GridBagConstraints.CENTER,
                         GridBagConstraints.EAST,
                         GridBagConstraints.SOUTHEAST,
                         GridBagConstraints.SOUTH,
                         GridBagConstraints.SOUTHWEST,
                         GridBagConstraints.WEST,
                         GridBagConstraints.NORTHWEST,
                         GridBagConstraints.NORTH,
                         GridBagConstraints.NORTHEAST};
        String n[] = {"Input", 
                      "Output", 
                      "hint...", 
                      "New", 
                      "Load", 
                      "Save", 
                      "Encode", 
                      "Decode", 
                      "Clear", 
                      "Copy"};
        name = n;
        int a[][] = {{0, 0, 1, 1, 0, 0, fill[3], anchor[5]}, 
                     {0, 1, 1, 1, 0, 0, fill[3], anchor[5]}, 
                     {0, 3, 7, 1, 0, 0, fill[3], anchor[5]}, 
                     {1, 0, 6, 1, 0, 0, fill[0], anchor[5]},
                     {1, 1, 6, 1, 0, 0, fill[0], anchor[5]}, 
                     {0, 2, 1, 1, 0, 0, fill[0], anchor[0]}, 
                     {1, 2, 1, 1, 0, 0, fill[0], anchor[0]}, 
                     {2, 2, 1, 1, 0, 0, fill[0], anchor[0]},
                     {3, 2, 1, 1, 0, 0, fill[0], anchor[0]}, 
                     {4, 2, 1, 1, 0, 0, fill[0], anchor[0]}, 
                     {5, 2, 1, 1, 0, 0, fill[0], anchor[0]}, 
                     {6, 2, 1, 1, 0, 0, fill[0], anchor[0]}};
        att = a;
        frame = new JFrame();
        GUIComponent = new ArrayList<JComponent>(12);
    }
    
    public void run() {
        frame.setSize(600, 160);
        frame.setLayout(new GridBagLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        int i;
        for (i = 0; i < 3; i++) {
            JLabel nLabel = new JLabel(name[i]);
            GUIComponent.add(nLabel);
        }
        for (i = 0; i < 2; i++) {
            JTextField nText = new JTextField("", 32);
            GUIComponent.add(nText);
        }
        for (i = 3; i < 10; i++) {
            JButton nButton = new JButton(name[i]);
            GUIComponent.add(nButton);
        }
        for (i = 0; i < GUIComponent.size(); i++) {
            addComponent(i);
        } 
        
        JTextField t = (JTextField) GUIComponent.get(3);
        t.addActionListener(this);
        t.addCaretListener(this);
        
        frame.setVisible(true);
    }

    private void addComponent(int i) {
        GridBagConstraints c = new GridBagConstraints();
        int a[] = att[i]; 
        
        c.gridx = a[0];
        c.gridy = a[1];
        c.gridwidth = a[2];
        c.gridheight = a[3];
        c.weightx = a[4];
        c.weighty = a[5];
        c.fill = a[6];
        c.anchor = a[7];
        frame.add(GUIComponent.get(i), c);
    }

    public void actionPerformed(ActionEvent event) {
        JTextField t2 = (JTextField) GUIComponent.get(3);
        userinput = t2.getText();
            
        JLabel t1 = (JLabel) GUIComponent.get(2);
        t1.setText("This is Input textfield. Your input is \'" + userinput + "\'");
    }
        
    public void caretUpdate(CaretEvent event) {
        JTextField t2 = (JTextField) GUIComponent.get(3);
        userinput = t2.getText();
            
        JLabel t1 = (JLabel) GUIComponent.get(2);
        t1.setText("This is Input textfield. Your input is \'" + userinput + "\'");
    } 
}
    
/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:EncryptorGUI.java
    功能:示範 Java 程式 
    作者:張凱慶
    時間:西元 2011 年 4 月 */


我們多 import 兩個套件 (package) ,分別是 java.awt.event 與 javax.swing.event
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;


這是因為 EncryptorGUI 需要實作兩個傾聽者介面,實做利用關鍵字 implements
public class EncryptorGUI implements ActionListener, CaretListener {


ActionListener 的名稱在 java.awt.event 之中,而 CaretListener 在 javax.swing.event 裡。兩者有什麼不同呢? ActionListener 須實作 actionPerformed()
public void actionPerformed(ActionEvent event) {
    JTextField t2 = (JTextField) GUIComponent.get(3);
    userinput = t2.getText();
            
    JLabel t1 = (JLabel) GUIComponent.get(2);
    t1.setText("This is Input textfield. Your input is \'" + userinput + "\'");
}


actionPerformed() 為使用者按下 Enter 鍵才會值行的方法 (method) ,因此常用在按鈕 (button) ,而在文字方塊中按下 Enter 鍵也相同。


注意這裡
JTextField t2 = (JTextField) GUIComponent.get(3);


從 GUIComponent 取出來的是 JComponent 的參考變數 (reference variable) ,因此我們得將其強制轉換為 JTextField 型態的參考變數,然後才可以用 JTextField 的 getText() 方法取得使用者輸入的文字。


userinput 為我們另外增加的屬性 (field) ,這用來暫存使用者的輸入值。


底下 JLabel 也是從 GUIComponent 取出來,經過強制型態轉換才可以用 setText() 方法, setText() 是在標籤中設定文字訊息。


CaretListener 須實作 caretUpdate()
public void caretUpdate(CaretEvent event) {
    JTextField t2 = (JTextField) GUIComponent.get(3);
    userinput = t2.getText();
            
    JLabel t1 = (JLabel) GUIComponent.get(2);
    t1.setText("This is Input textfield. Your input is \'" + userinput + "\'");
}


caretUpdate() 為文字方塊中有任何改變就會執行的方法。


最後, JTextField 必須登記相關的事件處理 (event handling)
JTextField t = (JTextField) GUIComponent.get(3);
t.addActionListener(this);
t.addCaretListener(this);


addActionListener() 與 addCaretListener() 各自以 this 為參數,這是因為我們在 EncryptorGUI 中實作,因此 this 就表示在同樣的類別 (class) 中。好了,來編譯執行看看吧!



記得,有改的類別檔案才要重新編譯。開始的視窗如下



輸入 H



多了事件處理, GUI 是不是變得有趣多了呢?可是按鈕也要進行事件處理啊!單一類別只能實做單一方法,這樣一來,不是每個按鈕都得進行相同工作了嗎?可是我們有七個按鈕耶!別擔心,我們可以在 inner 類別中實作傾聽者介面。


中英文術語對照
事件event
文字方塊textfield
標籤label
實作implement
套件package
方法method
按鈕button
參考變數reference variable
屬性field
事件處理event handling
類別class


您可以繼續參考
GUI 篇


相關目錄
回 Java 入門指南
回 Java 教材目錄
回首頁


參考資料
The JavaTM Tutorials: Getting Started
The JavaTM Tutorials: Learning the Java Language
The JavaTM Tutorials: Essential Classes
The Java Language Specification, Third Edition


本文於 2013 年 1 月訂正

沒有留言: