java丨事件驅動程式設計學習筆記(一)
一、事件和事件源
事件:事件可以定義為程式發生了某些事情的訊號 源物件(源元件):能建立一個事件並觸發該事件的元件成為源物件 事件類的根類:java.util.EventObject 可以使用EventObject類中的例項方法getSource()獲得事件的源物件 如果一個元件可以觸發某個事件,那麼這個事件的任意子類都可以觸發同類型的事件,如因為GUI元件的父類Component可以觸發MouseEvent、KeyEvent、FocusEvent和ComponentEvent,所以任意的GUI元件都可以觸發上述事件 二、監聽器、註冊以及處理事件 java使用一種基於委託的模型來處理事件:源物件觸發一個事件,對此事件感興趣的物件會處理它。將對此事件感興趣的物件稱為監聽器。 一個物件要稱為源物件上的事件監聽器,需要具備兩個條件: (1)監聽器物件的類必須是相應的事件監聽器介面的例項,以確保監聽器有處理這個事件的正確方法。 (2)監聽器物件必須由源物件註冊。註冊方法依賴於事件的型別。 下面我們編寫一個程式,使用兩個按鈕控制一個圓的大小
ControlCircle1.java
import javax.swing.*; import java.awt.*; public class ControlCircle1 extends JFrame{ private JButton jbtEnlarge = new JButton("Enlarge"); private JButton jbtShrink = new JButton("Shrink"); private CirclePanel canvas = new CirclePanel(); public ControlCircle1(){ JPanel panel = new JPanel();//Use the panel to group buttons //將兩個按鈕新增到面板中 panel.add(jbtEnlarge); panel.add(jbtShrink); this.add(canvas,BorderLayout.CENTER);//將畫布新增到中央 this.add(panel,BorderLayout.SOUTH);//將裝有兩個按鈕的面板新增到SOUTH的位置 } public static void main(String[] args){ JFrame frame = new ControlCircle1(); frame.setTitle("ControlCircle1"); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200,200); frame.setVisible(true); } } class CirclePanel extends JPanel{ private int radius = 5;//預設的圓的半徑 /**repaint the circle */ protected void paintComponent(Graphics g){ super.paintComponent(g); g.drawOval(getWidth()/2-radius,getHeight()/2-radius,2*radius,2*radius); } }
在完成了圖形介面設計之後,我們要實現通過按鈕來控制圓的大小 如何使用按鈕放大和縮小這個圓呢?當點選Enlarge按鈕時,希望能用一個比較大的半徑來重新繪製這個圓,如何實現?
(1)定義名為EnlargeListener和ShrinkListener的監聽器類,實現ActionListener (2)建立兩個監聽器,並且將它註冊到jbtEnlarge和jbtShrink (3)在CirclePanel中新增一個名為enlarge()的方法來增加半徑,新增一個名為shrink()的方法來縮小半徑,然後重新繪製面板 (4)實現EnlargeListener中的actionPerformed方法來呼叫canvas.enlarge()和canvas.shrink() (5)為了讓actionPerformed方法可以訪問引用變數canvas,將EnlargeListener定義為ControlCircle2類的內部類。內部類定義在另一個類中。 (6)為了避免編譯錯誤,CirclePanel類現在也定義為ControlCircle2的一個內部類 以下程式碼實現了通過Enlarge按鈕放大圓,通過Shrink按鈕縮小圓
ControlCircle2.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ControlCircle2 extends JFrame{
private JButton jbtEnlarge = new JButton("Enlarge");
private JButton jbtShrink = new JButton("Shrink");
private CirclePanel canvas = new CirclePanel();
public ControlCircle2(){
JPanel panel = new JPanel();//use the panel to group buttons
panel.add(jbtEnlarge);
panel.add(jbtShrink);
this.add(canvas,BorderLayout.CENTER);
this.add(panel,BorderLayout.SOUTH);
jbtEnlarge.addActionListener(new EnlargeListener());
jbtShrink.addActionListener(new ShrinkListener());
}
/**Main Method**/
public static void main(String[] args){
JFrame frame = new ControlCircle2();
frame.setTitle("ControlCircle2");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
}
//定義一個名為EnlargeListener的監聽器類,實現ActionListener
class EnlargeListener implements ActionListener{
public void actionPerformed(ActionEvent e){
canvas.enlarge();
}
}
//定義一個名為ShrinkListener的監聽器類,實現ActionListener
class ShrinkListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
canvas.shrink();
}
}
class CirclePanel extends JPanel{
private int radius = 5;//預設圓的半徑為5
/**Enlarge the circle */
public void enlarge(){
radius++;
repaint();
}
public void shrink() {
radius--;
repaint();
}
/**repaint the circle */
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawOval(getWidth()/2-radius,getHeight()/2-radius,2*radius,2*radius);
}
}
}
三、內部類 內部類或者巢狀類是定義在另一個類的範圍內的類 兩個獨立的類:
public class Test{
...
}
public class A{
...
}
public class Test{
...
//inner class
public class A{
...
}
}
內部類可以像常規類一樣使用。如果內部類只是被外部類使用,那就將該類定義為內部類。 一個內部類有如下的特徵: (1)一個內部類被編譯成一個名為OuterClassNameInnerlClassName.class的類。例如:Test中的A被編譯為TestInnerlClassName.class的類。例如:Test中的A被編譯為TestA.class。 (2)內部類可以引用定義在它巢狀的外部類中的資料和方法,所以,不需要將外部類物件的引用傳遞給內部類的構造方法。因此,內部類可以使程式更加簡單和簡潔 (3)使用可見性修飾符定義內部類時,遵從和應用與在類成員上一樣的可見性規則, (4)可以將內部類定義為static。一個static內部類可以使用外部類的名字訪問。一個static類是不能訪問外部類的非靜態成員的。 (5)內部類的物件經常在外部類中建立。但是,也可以從另一個類中建立一個內部類的物件。如果該內部類是非靜態的,那就必須先建立一個外部類的例項,然後使用下面的語法建立一個內部類的物件: OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 如果內部類是靜態的,那麼使用下面的語法為它建立一個物件: OuterClass.InnerClass innerObject = new OuterClass.InnerClass(); 內部類的一個簡單應用就是將從屬類合併到主類中。這可以減少原始檔的數量。例如,將類A合併到類Test中,只建立一個原始檔Test.java,最終的類檔案是Test.class和Test$A.class 內部類的另一個實際應用是為了避免類命名衝突