事件處理可以簡單地這麼理解,當有一個事件產生,程序要根據這個事件做出響應。比如,我們做了一個可以通過按鈕改變背景顏色的窗口,當我們點擊按鈕時便產生了一個事件,程序會根據這個事件來做出響應,也就是去改變背景的顏色。
運行結果
那麼程序是怎樣做出響應的呢?這就需要事件監聽器ActionListener,這是一個接口,裡面包含了actionPerformed方法(也就是根據事件去執行的操作),所以我們要實現這個接口(實現接口裡的actionPerformed方法)做出一個監聽器對象出來,並且用按鈕來注冊這個監聽器對象,這樣當按鈕被點擊的時候,就會調用這個監聽器來執行響應了。
事件處理機制
代碼(第42行開始為實現接口):
1 package buttonPanel;-------------------------------------------------------------------------------------------------------------------------
在上述代碼中,為了方便監聽器調用buttonPanel,將ColorAction作為ButtonFrame的內部類。如果將ColorAction類獨立出去,需要將buttonPanel傳遞到ColorAction,實現如下:
1 package buttonPanel2; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 public class ButtonFrame2 extends JFrame { 8 private ButtonPanel buttonPanel; 9 private static final int DEFAULT_WIDTH = 300; 10 private static final int DEFAULT_HEIGHT = 200; 11 12 public ButtonFrame2() { 13 setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT); 14 setLocationByPlatform(true); 15 16 JButton redButton = new JButton("RED"); 17 JButton yellowButton = new JButton("YELLOW"); 18 JButton blueButton = new JButton("BLUE"); 19 20 buttonPanel = new ButtonPanel(); 21 22 buttonPanel.add(redButton); 23 buttonPanel.add(yellowButton); 24 buttonPanel.add(blueButton); 25 26 add(buttonPanel); 27 28 //將此對象通過this傳到ColorAction的構造器。 29 ColorAction redAction = new ColorAction(this,Color.red); 30 ColorAction yellowAction = new ColorAction(this,Color.yellow); 31 ColorAction blueAction = new ColorAction(this,Color.blue); 32 33 redButton.addActionListener(redAction); 34 yellowButton.addActionListener(yellowAction); 35 blueButton.addActionListener(blueAction); 36 } 37 38 public void setButtonPanelsBackground(Color backgroundColor) { 39 buttonPanel.setBackground(backgroundColor); 40 } 41 42 public static void main(String[] args) { 43 EventQueue.invokeLater(new Runnable() { 44 public void run() { 45 JFrame frame = new ButtonFrame2(); 46 frame.setTitle("ColorButton"); 47 frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 48 frame.setVisible(true); 49 } 50 }); 51 } 52 } 53 54 class ColorAction implements ActionListener { 55 private ButtonFrame2 buttonFrame; 56 private Color backgroundColor; 57 58 //通過構造器的方法把ButtonFrame2對象傳過來,這個對象包含了成員變量buttonPanel,以便對其更換背景色。 59 public ColorAction(ButtonFrame2 buttonFrame,Color c) { 60 this.buttonFrame = buttonFrame; //this.buttonFrame只是對象管理者,管理的還是ButtonFrame的對象frame。 61 backgroundColor = c; 62 } 63 public void actionPerformed(ActionEvent event) { 64 buttonFrame.setButtonPanelsBackground(backgroundColor); 65 //這是我們在ButtonFrame2中添加的新方法。 66 } 67 } 68 69 class ButtonPanel extends JPanel { 70 private static final int DEFAUT_WIDTH = 300; 71 private static final int DEFAUT_HEIGHT = 200; 72 73 public ButtonPanel() { 74 setBackground(Color.pink); 75 } 76 77 @Override 78 protected void paintComponent(Graphics g) { 79 g.create(); 80 super.paintComponent(g); 81 } 82 83 @Override 84 public Dimension getPreferredSize() { 85 return new Dimension(DEFAUT_WIDTH,DEFAUT_HEIGHT); 86 } 87 }ButtonFrame2
--------------------------------------------------------------------------------------------------------
代碼存在一個缺陷,就是在構造按鈕、添加按鈕到面板、構造相應顏色的監聽器和注冊監聽器的時候有代碼復制的情況,為了避免代碼復制,我們可以創建一個makeButton方法,把這些重復的操作包含在內,實現如下:
1 package buttonPanel3; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 public class ButtonFrame3 extends JFrame { 8 private ButtonPanel buttonPanel; 9 private static final int DEFAULT_WIDTH = 300; 10 private static final int DEFAULT_HEIGHT = 200; 11 12 public ButtonFrame3() { 13 setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT); 14 setLocationByPlatform(true); 15 16 buttonPanel = new ButtonPanel(); 17 add(buttonPanel); 18 19 makeButton("RED",Color.red); 20 makeButton("YELLOW",Color.yellow); 21 makeButton("BLUE",Color.blue); 22 } 23 24 //為了避免代碼重復,我們將重復的操作放在這個函數裡。 25 public void makeButton(String name,final Color bg) { 26 JButton button = new JButton(name); 27 buttonPanel.add(button); 28 button.addActionListener(new ActionListener() { //可以new一個接口出來,但是後面必須接花括號實現內部方法。 29 public void actionPerformed(ActionEvent event) { 30 buttonPanel.setBackground(bg); 31 } 32 }); 33 } 34 35 public static void main(String[] args) { 36 EventQueue.invokeLater(new Runnable() { 37 public void run() { 38 JFrame frame = new ButtonFrame3(); 39 frame.setTitle("ColorButton"); 40 frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 41 frame.setVisible(true); 42 } 43 }); 44 } 45 } 46 47 class ButtonPanel extends JPanel { 48 private static final int DEFAUT_WIDTH = 300; 49 private static final int DEFAUT_HEIGHT = 200; 50 51 @Override 52 protected void paintComponent(Graphics g) { 53 g.create(); 54 super.paintComponent(g); 55 } 56 57 @Override 58 public Dimension getPreferredSize() { 59 return new Dimension(DEFAUT_WIDTH,DEFAUT_HEIGHT); 60 } 61 }
在代碼中,監聽器只被調用了一次,也就是在addActionListener()時。所以我們沒有必要為監聽器單獨做一個類出來,而是只需在用到監聽器時直接new一個ActionListener接口出來,並在花括號裡實現接口方法即可。
--------------------------------------------------------------------------------------------------------
但是有些程序員喜歡將因事件而改變的容器作為實現接口的監聽器,代碼如下,這樣會顯得混亂,我們不建議這麼做:
1 package buttonPanel4; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 //將buttonPanel所在的ButtonFrame4實現接口。 8 public class ButtonFrame4 extends JFrame implements ActionListener { 9 private ButtonPanel buttonPanel; 10 private static final int DEFAULT_WIDTH = 300; 11 private static final int DEFAULT_HEIGHT = 200; 12 13 public ButtonFrame4() { 14 setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT); 15 setLocationByPlatform(true); 16 17 buttonPanel = new ButtonPanel(); 18 add(buttonPanel); 19 20 makeButton("RED"); 21 makeButton("YELLOW"); 22 makeButton("BLUE"); 23 } 24 25 public void makeButton(String name) { 26 JButton button = new JButton(name); 27 buttonPanel.add(button); 28 button.addActionListener(this); 29 //直接注冊this這個接口。 30 } 31 32 //覆蓋接口方法,String getActionCommand()為java.awt.event.ActionEvent的方法,返回動作事件相關的命令字符串,在這裡等於按鈕標簽。 33 //需要用到if else選擇語句。 34 @Override 35 public void actionPerformed(ActionEvent event) { 36 String c = event.getActionCommand(); 37 if(c == "RED") { 38 buttonPanel.setBackground(Color.red); 39 }else if(c == "YELLOW") { 40 buttonPanel.setBackground(Color.yellow); 41 }else { 42 buttonPanel.setBackground(Color.blue); 43 } 44 } 45 46 public static void main(String[] args) { 47 EventQueue.invokeLater(new Runnable() { 48 public void run() { 49 JFrame frame = new ButtonFrame4(); 50 frame.setTitle("ColorButton"); 51 frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 52 frame.setVisible(true); 53 } 54 }); 55 } 56 } 57 58 class ButtonPanel extends JPanel { 59 private static final int DEFAUT_WIDTH = 300; 60 private static final int DEFAUT_HEIGHT = 200; 61 62 @Override 63 protected void paintComponent(Graphics g) { 64 g.create(); 65 super.paintComponent(g); 66 } 67 68 @Override 69 public Dimension getPreferredSize() { 70 return new Dimension(DEFAUT_WIDTH,DEFAUT_HEIGHT); 71 } 72 }