Java基础学习 -- GUI之 事件处理基础
事件处理可以简单地这么理解,当有一个事件产生,程序要根据这个事件做出响应。比如,我们做了一个可以通过按钮改变背景颜色的窗口,当我们点击按钮时便产生了一个事件,程序会根据这个事件来做出响应,也就是去改变背景的颜色。
运行结果
那么程序是怎样做出响应的呢?这就需要事件监听器ActionListener,这是一个接口,里面包含了actionPerformed方法(也就是根据事件去执行的操作),所以我们要实现这个接口(实现接口里的actionPerformed方法)做出一个监听器对象出来,并且用按钮来注册这个监听器对象,这样当按钮被点击的时候,就会调用这个监听器来执行响应了。
事件处理机制
代码(第42行开始为实现接口):
1 package buttonPanel; 2 3 import java.awt.*; 4 import java.awt.event.*; //事件监听器接口ActionListener的位置。 5 import javax.swing.*; 6 7 public class ButtonFrame 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 ButtonFrame() { 13 setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT); 14 setLocationByPlatform(true); 15 16 //构造按钮 17 JButton redButton = new JButton("RED"); 18 JButton yellowButton = new JButton("YELLOW"); 19 JButton blueButton = new JButton("BLUE"); 20 21 buttonPanel = new ButtonPanel(); 22 23 //添加按钮到面板 24 buttonPanel.add(redButton); 25 buttonPanel.add(yellowButton); 26 buttonPanel.add(blueButton); 27 28 add(buttonPanel); 29 30 //构造对应颜色的动作监听器 31 ColorAction redAction = new ColorAction(Color.red); 32 ColorAction yellowAction = new ColorAction(Color.yellow); 33 ColorAction blueAction = new ColorAction(Color.blue); 34 35 //每个按钮注册对应的监听器 36 redButton.addActionListener(redAction); 37 yellowButton.addActionListener(yellowAction); 38 blueButton.addActionListener(blueAction); 39 } 40 41 //为了方便调用buttonPanel,将ColorAction作为ButtonFrame的内部类。 42 private class ColorAction implements ActionListener { 43 private Color backgroundColor; 44 public ColorAction(Color c) { 45 backgroundColor = c; 46 } 47 public void actionPerformed(ActionEvent event) { 48 buttonPanel.setBackground(backgroundColor); 49 } 50 } 51 52 public static void main(String[] args) { 53 EventQueue.invokeLater(new Runnable() { 54 public void run() { 55 JFrame frame = new ButtonFrame(); 56 frame.setTitle("ColorButton"); 57 frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 58 frame.setVisible(true); 59 } 60 }); 61 } 62 } 63 64 class ButtonPanel extends JPanel { 65 private static final int DEFAUT_WIDTH = 300; 66 private static final int DEFAUT_HEIGHT = 200; 67 68 @Override 69 protected void paintComponent(Graphics g) { 70 g.create(); 71 super.paintComponent(g); 72 } 73 74 @Override 75 public Dimension getPreferredSize() { 76 return new Dimension(DEFAUT_WIDTH,DEFAUT_HEIGHT); 77 } 78 }
-------------------------------------------------------------------------------------------------------------------------
在上述代码中,为了方便监听器调用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 }
--------------------------------------------------------------------------------------------------------
代码存在一个缺陷,就是在构造按钮、添加按钮到面板、构造相应颜色的监听器和注册监听器的时候有代码复制的情况,为了避免代码复制,我们可以创建一个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 }