第一部分:理论知识
第11章 事件处理(事件处理基础; 动作; 鼠标事件;AWT事件继承层次)
1. 事件源(event source):能够产生事件的对象都可 以成为事件源,如文本框、按钮等。一个事件源是一个 能够注册监听器并向监听器发送事件对象的对象。
2. 事件监听器(event listener):事件监听器对象接 收事件源发送的通告(事件对象),并对发生的事件作 出响应。一个监听器对象就是一个实现了专门监听器接 口的类实例,该类必须实现接口中的方法,这些方法当 事件发生时,被自动执行。
3. 事件对象(event object):Java将事件的相关信息 封装在一个事件对象中,所有的事件对象都最终派生于 java.util.EventObject类。不同的事件源可以产生不 同类别的事件
4.AWT事件处理机制的概要:
(1) 监听器对象:是一个实现了特定监听器接口( listener interface)的类实例。
(2)事件源:是一个能够注册监听器对象并发送事件对 象的对象。
(3)当事件发生时,事件源将事件对象自动传递给所 有注册的监听器。
(4) 监听器对象利用事件对象中的信息决定如何对事 件做出响应。
5.GUI设计中,程序员需要对组件的某种事件进行响应和处理时,必须完成两个步骤:
(1) 定义实现某事件监听器接口的事件监听器类,并具体化接口中声明的事件处理抽象方法。
(2) 为组件注册实现了规定接口的事件监听器对象;
6.注册监听器方法 eventSourceObject.addEventListener(eventListenerObject)
下面是监听器的一个示例: ActionListener listener = …;
JButton button=new JButton(“Ok”); button.addActionListener(listener);
7.动作事件(ActionEvent):当特定组件动作(点 击按钮)发生时,该组件生成此动作事件。
(1) 该 事 件 被 传 递 给 组 件 注 册 的 每 一 个 ActionListener 对象, 并 调 用 监 听 器 对 象 的 actionPerformed方法以接收这类事件对象。
(2)能够触发动作事件的动作,主要包括:
1) 点击按钮
2) 双击一个列表中的选项;
3) 选择菜单项;
4) 在文本框中输入回车。
8. 监听器接口的实现
监听器类必须实现与事件源相对应的接口,即必须提供接口中方法的实现。
⚫ 监听器接口方法实现
class Mylistener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{ …… }
}
9.命令按钮Jbutton主要API
a.创建按钮对象
JButton类常用的一组构造方法:
(1) JButton(String text):创建一个带文本的按钮。
(2) JButton(Icon icon) :创建一个带图标的按钮。
(3)JButton(String text, Icon icon) :创建一个带文本和图标
的按钮。
b.按钮对象的常用方法
① getLabel( ):返回按钮的标签字符串;
② setLabel(String s):设置按钮的标签为字符串s。
10. 用匿名类、lambda表达式简化程序
例ButtonTest.java中,各按钮需要同样的处理:
1) 使用字符串构造按钮对象;
2) 把按钮添加到面板上;
3) 用对应的颜色构造一个动作监听器;
4) 注册动作监听器。
11.适配器类
12.用匿名类简化
13.动作事件
14.鼠标事件
第二部分:实验部分
实验十三 图形界面事件处理技术
实验时间 2018-11-22
1、实验目的与要求
(1) 掌握事件处理的基本原理,理解其用途;
(2) 掌握AWT事件模型的工作机制;
(3) 掌握事件处理的基本编程模型;
(4) 了解GUI界面组件观感设置方法;
(5) 掌握WindowAdapter类、AbstractAction类的用法;
(6) 掌握GUI程序中鼠标事件处理技术。
2、实验内容和步骤
实验1: 导入第11章示例程序,测试程序并进行代码注释。
测试程序1:
l 在elipse IDE中调试运行教材443页-444页程序11-1,结合程序运行结果理解程序;
l 在事件处理相关代码处添加注释;
l 用lambda表达式简化程序;
l 掌握JButton组件的基本API;
l 掌握Java中事件处理的基本编程模型。
package First;
import java.awt.*;
import javax.swing.*;
/**
* @version 1.34 2015-06-12
* @author Cay Horstmann
*/
public class ButtonTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(() -> {
JFrame frame = new ButtonFrame();//创建对象;超类量引用子类对象;
frame.setTitle("ButtonTest");//程序/软件的名字
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭操作;
frame.setVisible(true);//使界面可视化;
});
}
}
1 package First;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 /**
8 * A frame with a button panel
9 */
10 public class ButtonFrame extends JFrame {
11 private JPanel buttonPanel;
12 private static final int DEFAULT_WIDTH = 300*2;
13 private static final int DEFAULT_HEIGHT = 200*2;
14
15 public ButtonFrame() {
16 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
17 buttonPanel = new JPanel();
18 makeButton("黄色", Color.yellow);
19 makeButton("蓝色", Color.blue);
20 makeButton("红色", Color.red);
21 makeButton("绿色",Color.green);
22 //添加面板到框架里
23 add(buttonPanel);
24
25 }
26
27 protected void makeButton(String name,Color backgound) {
28 // 创建按钮
29 JButton button = new JButton(name);
30 // //把按钮添加到面板上
31 buttonPanel.add(button);
32 // create button actions
33 //方法一:通过内部类方式实现
34 /*
35 //构造一个对象,并将对象设置为按钮监听器
36 ColorAction action = new ColorAction(backgound);
37 // 为按钮添加监听器
38 button.addActionListener(action);*/
39 //方法二:匿名内部类方式实现
40 /*button.addActionListener(new ActionListener() {
41
42 @Override
43 public void actionPerformed(ActionEvent e) {
44 // TODO 自动生成的方法存根
45 buttonPanel.setBackground(backgound);
46 }
47 });*/
48 //方法三通过lambad表达式实现
49 button.addActionListener((e)->{
50 buttonPanel.setBackground(backgound);
51 });
52
53 }
54
55 /**
56 * An action listener that sets the panel's background color.
57 */
58 //这是实现了 ActionListener接口的内部类
59 /*private class ColorAction implements ActionListener {
60 private Color backgroundColor;
61
62 public ColorAction(Color c) {
63 backgroundColor = c;
64 }
65 //实现ActionListener接口,监听器类必须有一个actionPerformed方法
66 public void actionPerformed(ActionEvent event) {
67 buttonPanel.setBackground(backgroundColor);
68 }
69 }*/
70
测试程序2:
l 在elipse IDE中调试运行教材449页程序11-2,结合程序运行结果理解程序;
l 在组件观感设置代码处添加注释;
l 了解GUI程序中观感的设置方法。
1 package Second;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 /**
7 * @version 1.32 2015-06-12
8 * @author Cay Horstmann
9 */
10 public class PlafTest
11 {
12 public static void main(String[] args)
13 {
14 EventQueue.invokeLater(() -> {
15 JFrame frame = new PlafFrame();
16 frame.setTitle("PlafTest");
17 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
18 frame.setVisible(true);
19 });
20 }
21 }
1 package Second;
2
3 import javax.swing.JButton;
4 import javax.swing.JFrame;
5 import javax.swing.JPanel;
6 import javax.swing.SwingUtilities;
7 import javax.swing.UIManager;
8
9 /**
10 * A frame with a button panel for changing look-and-feel
11 */
12 public class PlafFrame extends JFrame
13 {
14 private JPanel buttonPanel;
15
16 public PlafFrame()
17 {
18 buttonPanel = new JPanel();
19 //获取所有安装的观感实现
20
21 UIManager.LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels();
22 for (UIManager.LookAndFeelInfo info : infos)
23 makeButton(info.getName(), info.getClassName());
24
25 add(buttonPanel);
26 pack();
27 }
28
29 /**
30 * Makes a button to change the pluggable look-and-feel.
31 * @param name the button name
32 * @param className the name of the look-and-feel class
33 */
34 private void makeButton(String name, String className)
35 {
36 // 向面板添加按钮;
37
38 JButton button = new JButton(name);
39 buttonPanel.add(button);
40
41 // 设置按钮动作;
42
43 button.addActionListener(event -> {
44 // 按钮动作:切换到新的外观和感觉
45 try
46 {
47 UIManager.setLookAndFeel(className);
48 //调用静态方法,刷新全部的组件集。这里需要向方法提供一个组件,并由此找到其他的所有组件
49 //外部对象的this引用必须将外部类名作为前缀
50
51 SwingUtilities.updateComponentTreeUI(this);
52 pack();
53 }
54 catch (Exception e)
55 {
56 e.printStackTrace();
57 }
58 });
59 }
60 }
测试程序3:
l 在elipse IDE中调试运行教材457页-458页程序11-3,结合程序运行结果理解程序;
l 掌握AbstractAction类及其动作对象;
l 掌握GUI程序中按钮、键盘动作映射到动作对象的方法。
1 package Third;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 /**
7 * @version 1.34 2015-06-12
8 * @author Cay Horstmann
9 */
10 public class ActionTest
11 {
12 public static void main(String[] args)
13 {
14 EventQueue.invokeLater(() -> {
15 JFrame frame = new ActionFrame();
16 frame.setTitle("ActionTest");
17 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
18 frame.setVisible(true);
19 });
20 }
21 }
1 package Third;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 /**
8 * A frame with a panel that demonstrates color change actions.
9 */
10 public class ActionFrame extends JFrame
11 {
12 private JPanel buttonPanel;
13 private static final int DEFAULT_WIDTH = 300;
14 private static final int DEFAULT_HEIGHT = 200;
15
16 public ActionFrame()
17 {
18 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
19
20 buttonPanel = new JPanel();
21
22 // define actions
23 Action yellowAction = new ColorAction("Yellow", new ImageIcon("yellow-ball.gif"),
24 Color.YELLOW);
25 Action blueAction = new ColorAction("Blue", new ImageIcon("blue-ball.gif"), Color.BLUE);
26 Action redAction = new ColorAction("Red", new ImageIcon("red-ball.gif"), Color.RED);
27
28 //用Action对象构造按钮,把动作和按钮关联起来
29
30 buttonPanel.add(new JButton(yellowAction));
31 buttonPanel.add(new JButton(blueAction));
32 buttonPanel.add(new JButton(redAction));
33
34 // add panel to frame
35 add(buttonPanel);
36
37 //得到顶层组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射
38
39 // associate the Y, B, and R keys with names
40 InputMap imap = buttonPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
41 //将(按键,动作键)添加到输入映射中
42 imap.put(KeyStroke.getKeyStroke("ctrl Y"), "panel.yellow");
43 imap.put(KeyStroke.getKeyStroke("ctrl B"), "panel.blue");
44 imap.put(KeyStroke.getKeyStroke("ctrl R"), "panel.red");
45
46 // associate the names with actions、
47 //得到顶层组件的动作映射
48 ActionMap amap = buttonPanel.getActionMap();
49 //将(动作键,动作对象)添加到映射中
50
51 amap.put("panel.yellow", yellowAction);
52 amap.put("panel.blue", blueAction);
53 amap.put("panel.red", redAction);
54 }
55
56 public class ColorAction extends AbstractAction
57 {
58 /**
59 * Constructs a color action.
60 * @param name the name to show on the button
61 * @param icon the icon to display on the button
62 * @param c the background color
63 */
64 public ColorAction(String name, Icon icon, Color c)
65 {
66 //存储命令的名称、图标、简要说明和需要的颜色
67 putValue(Action.NAME, name);
68 putValue(Action.SMALL_ICON, icon);
69 putValue(Action.SHORT_DESCRIPTION, "Set panel color to " + name.toLowerCase());//显示在工具提示里
70
71 putValue("color", c);
72 }
73
74 public void actionPerformed(ActionEvent event)
75 {
76 Color c = (Color) getValue("color");
77 buttonPanel.setBackground(c);
78 }
79 }
80 }
测试程序4:
l 在elipse IDE中调试运行教材462页程序11-4、11-5,结合程序运行结果理解程序;
l 掌握GUI程序中鼠标事件处理技术。
1 package Forth;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 /**
7 * @version 1.34 2015-06-12
8 * @author Cay Horstmann
9 */
10 public class MouseTest
11 {
12 public static void main(String[] args)
13 {
14 EventQueue.invokeLater(() -> {
15 JFrame frame = new MouseFrame();
16 frame.setTitle("MouseTest");
17 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
18 frame.setVisible(true);
19 });
20 }
21 }
1 package Forth;
2
3 import javax.swing.*;
4
5 /**
6 * A frame containing a panel for testing mouse operations
7 */
8 public class MouseFrame extends JFrame
9 {
10 public MouseFrame()
11 {
12 add(new MouseComponent());
13 pack();
14 }
15 }
1 package Forth;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import java.awt.geom.*;
6 import java.util.*;
7 import javax.swing.*;
8
9 /**
10 * A component with mouse operations for adding and removing squares.
11 */
12 public class MouseComponent extends JComponent
13 {
14 private static final int DEFAULT_WIDTH = 300;
15 private static final int DEFAULT_HEIGHT = 200;
16
17 private static final int SIDELENGTH = 10;
18 private ArrayList<Rectangle2D> squares;
19 private Rectangle2D current; // the square containing the mouse cursor
20
21 public MouseComponent()
22 {
23 squares = new ArrayList<>();
24 current = null;
25
26 addMouseListener(new MouseHandler());
27 addMouseMotionListener(new MouseMotionHandler());
28 }
29
30 public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
31
32 public void paintComponent(Graphics g)
33 {
34 Graphics2D g2 = (Graphics2D) g;
35
36 // draw all squares
37 for (Rectangle2D r : squares)
38 g2.draw(r);
39 }
40
41 /**
42 * Finds the first square containing a point.
43 * @param p a point
44 * @return the first square that contains p
45 */
46 public Rectangle2D find(Point2D p)
47 {
48 for (Rectangle2D r : squares)
49 {
50 if (r.contains(p)) return r;
51 }
52 return null;
53 }
54
55 /**
56 * Adds a square to the collection.
57 * @param p the center of the square
58 */
59 public void add(Point2D p)
60 {
61 double x = p.getX();
62 double y = p.getY();
63
64 current = new Rectangle2D.Double(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH,
65 SIDELENGTH);
66 squares.add(current);
67 repaint();
68 }
69
70 /**
71 * Removes a square from the collection.
72 * @param s the square to remove
73 */
74 public void remove(Rectangle2D s)
75 {
76 if (s == null) return;
77 if (s == current) current = null;
78 squares.remove(s);
79 repaint();
80 }
81
82 //两个独立的接口MouseListener和MouseMotionListener,有利于提高效率。
83 //当用户移动鼠标时,只关心鼠标点击的监听器就不会被多余的鼠标移动所困扰。
84 private class MouseHandler extends MouseAdapter
85 {
86 public void mousePressed(MouseEvent event)
87 {
88 // add a new square if the cursor isn't inside a square
89 //getPoint方法返回事件源组件左上角的x y坐标
90 //判断该处是否已经绘制图形
91 current = find(event.getPoint());
92 if (current == null) add(event.getPoint());
93 }
94
95 public void mouseClicked(MouseEvent event)
96 {
97 // remove the current square if double clicked
98 current = find(event.getPoint());
99 //双击鼠标,擦除方块
100 if (current != null && event.getClickCount() >= 2) remove(current);
101 }
102 }
103
104 private class MouseMotionHandler implements MouseMotionListener
105 {
106 //移动鼠标的同时按下鼠标,调用mouseMoved
107 public void mouseMoved(MouseEvent event)
108 {
109 // set the mouse cursor to cross hairs if it is inside
110 // a rectangle
111 //光标在一个小方块之上时变成另外一种形状(十字)
112 if (find(event.getPoint()) == null) setCursor(Cursor.getDefaultCursor());
113 else setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
114 }
115
116 //更新光标位置
117 public void mouseDragged(MouseEvent event)
118 {
119 if (current != null)
120 {
121 int x = event.getX();
122 int y = event.getY();
123 //设置形状坐标和大小
124 // drag the current rectangle to center it at (x, y)
125 current.setFrame(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH, SIDELENGTH);
126 repaint();
127 }
128 }
129 }
130 }
实验2:结对编程练习
利用班级名单文件、文本框和按钮组件,设计一个有如下界面(图1)的点名器,要求用户点击开始按钮后在文本输入框随机显示2017级网络与信息安全班同学姓名,如图2所示,点击停止按钮后,文本输入框不再变换同学姓名,此同学则是被点到的同学姓名。
图1 点名器启动界面
图2 点名器点名界面
1 package practise1;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6
7
8
9 public class RandomName {
10
11 public static void main(String[] args) {
12 // TODO Auto-generated method stub
13
14 {
15 EventQueue.invokeLater(() -> {
16 JFrame A= new ButtonFrame();
17 A.setTitle("点名器");
18 A.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
19 A.setVisible(true);
20 });
21 }
22 }
23
24 }
1 package practise1;
2
3 import java.awt.Color;
4 import java.awt.Container;
5 import java.awt.event.*;
6 import java.io.*;
7 import java.util.*;
8 import java.util.Timer;
9
10 import javax.swing.*;
11
12 public class ButtonFrame extends JFrame {
13 private ArrayList arrayList;
14
15
16
17 {
18 arrayList = new ArrayList<>();
19 //读文件
20 File file = new File("H:/List.txt");
21 FileInputStream fis;
22 try {
23 fis = new FileInputStream(file);
24 InputStreamReader in = new InputStreamReader(fis);
25 BufferedReader buf = new BufferedReader(in);
26 String readLine;
27 while ((readLine = buf.readLine())!=null) {
28 arrayList.add(readLine);
29
30 }
31 } catch (FileNotFoundException e1) {
32 // TODO Auto-generated catch block
33 e1.printStackTrace();
34 } catch (IOException e1) {
35 // TODO Auto-generated catch block
36 e1.printStackTrace();
37 }
38 }
39 private JPanel buttonPanel;
40 private static final int DEFAULT_WIDTH = 500;
41 private static final int DEFAULT_HEIGHT = 300;
42
43
44
45 public ButtonFrame() {
46 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
47 buttonPanel = new JPanel();
48 buttonPanel.setLayout(null);
49 JLabel jLabel = new JLabel("随机点名器");
50 JButton jButton = new JButton("开始");
51 jLabel.setBounds(200, 40, 65, 40);
52 jButton.setBounds(200, 90, 65, 40);
53
54
55
56 jButton.addActionListener(new ActionListener() {
57
58 Timer timer;
59
60
61
62 public void actionPerformed(ActionEvent e) {
63
64 if (jButton.getText().equals("开始")) {
65
66 timer = new Timer();;
67
68 TimerTask timerTask = new TimerTask() {
69
70 public void run() {
71
72 jButton.setText("停止");
73
74 jButton.setBackground(Color.red);
75
76 jLabel.setText((String) arrayList.get((int) (Math.random() * 43)));
77
78 }
79
80
81
82 };
83
84 timer.schedule(timerTask, 0, 10);
85
86 }
87
88 if (jButton.getText().equals("停止")) {
89
90 timer.cancel();
91
92 jButton.setText("开始");
93
94 jButton.setBackground(Color.gray);
95
96 }
97
98 }
99
100 });
101
102
103
104
105 buttonPanel.add(jLabel);
106 buttonPanel.add(jButton);
107 add(buttonPanel);
108
109 }
110
111
112 }
实验总结:
测试程序环节当中,第一个测试程序花费的时间挺长的,对于将程序改成Lambda表达式还是不太懂。在结对编程环节当中,完全没有任何的思路,想了很久还是不知道从何下手。看了学长的程序之后,还是不会。