上篇博客中介绍了界面的实现方法,在这篇博客中将对每个按钮的功能的实现进行讲解并介绍重绘
首先肯定要添加事件监听机制了,那么问题来了,事件源对象是谁?需要添加什么方法?事件接口是什么?
1、我们需要点击按钮,获取按钮上的文字信息,颜色信息,粗细信息。那么,此时事件源对象就是按钮,监听方法就是addActionListener(ActionListener e),事件接口就是ActionListener
2、要根据在窗体上按下和释放的位置画一个图形,此时事件源对象就是窗体,监听方法就是addMouseListener(MouseListener e),事件接口就是MouseListener
1 public class DrawListener extends MouseAdapter implements ActionListener {
2
3 private Color color = Color.black;// 声明颜色属性,存储用户选择的颜色
4 private int width = 1;// 声明粗细属性,存储用户选择的粗细
5 private String type = "Line";// 声明图形属性,存储用户选择的图形
6 private int x1, y1, x2, y2, x3 = 0, y3 = 0, x4 = 0, y4 = 0, x5, y5;// 声明坐标值属性,存储鼠标按下和释放的坐标值
7 private Graphics2D g;// 声明画笔类属性,组件是画出来的,现在要在组件上画图形,Graphics从组件上获取
8 private DrawMain dm;// 声明画图程序窗体组件属性
9 private JTextField text;// 获取文本框内容
10 private double H = 100;// 等腰三角形的高度
11 private int num = 0;
12 private List<Shape> list;
13 private ImageIcon i = new ImageIcon("C:\\Users\\long452a\\Desktop\\a1.jpg");
14
15 /**
16 * 构造方法
17 *
18 * @param dm画图程序的窗体组件对象
19 */
20 public DrawListener(DrawMain dm, JTextField text, List<Shape> list) {
21 this.dm = dm;
22 this.text = text;
23 this.list = list;
24 }
25
26 /**
27 * 点击按钮时执行的事件处理方法
28 *
29 * @param e对象中存储了事件源对象的信息和动作信息
30 */
31 public void actionPerformed(ActionEvent e) {
32 }
33
34 /**
35 * Invoked when the mouse button has been clicked (pressed and released) on a
36 * component.
37 */
38 public void mouseClicked(MouseEvent e) {
39 }
40
41 /**
42 * Invoked when a mouse button has been pressed on a component.
43 */
44 public void mousePressed(MouseEvent e) {
45 }
46
47 /**
48 * Invoked when a mouse button has been released on a component.
49 */
50 public void mouseReleased(MouseEvent e) {
51 }
52
53 public void mouseDragged(MouseEvent e) {
54 }
55 }
这样我们的类就建好了,下面就该写里面的方法了
1 /**
2 * 点击按钮时执行的事件处理方法
3 *
4 * @param e对象中存储了事件源对象的信息和动作信息
5 */
6 public void actionPerformed(ActionEvent e) {
7 String text = e.getActionCommand();
8 if (text.equals("")) {
9 JButton button = (JButton) e.getSource();
10 color = button.getBackground();
11 } else if (text.equals("1") || text.equals("3") || text.equals("5")) {
12 width = Integer.parseInt(text);
13 } else {
14 type = text;
15 }
16 // System.out.println(color + ">>" + width + ">>" + type);
17 }
18
19 /**
20 * Invoked when the mouse button has been clicked (pressed and released) on a
21 * component.
22 */
23 public void mouseClicked(MouseEvent e) {
24 x4 = x2;
25 y4 = y2;
26 }
27
28 /**
29 * Invoked when a mouse button has been pressed on a component.
30 */
31 public void mousePressed(MouseEvent e) {
32 x1 = e.getX() + 7;
33 y1 = e.getY() + 183;
34 if (y1 < 183)
35 y1 = 183;
36 g = (Graphics2D) dm.getGraphics();// 从窗体上获取画笔对象
37 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 设置画笔抗锯齿
38 g.setColor(color);// 设置画笔颜色
39 g.setStroke(new BasicStroke(width));// 设置画笔线条粗细
40
41 }
42
43 /**
44 * Invoked when a mouse button has been released on a component.
45 */
46 public void mouseReleased(MouseEvent e) {
47 x2 = e.getX() + 7;
48 y2 = e.getY() + 183;
49 if (y2 < 183)
50 y2 = 183;
51 if (type.equals("iso_Tri")) {
52 if (x1 == x2) {
53 g.drawLine(x1, y1, x2, y2);
54 g.drawLine(x1, y1, x1 + (int) H, (y2 + y1) / 2);
55 g.drawLine(x2, y2, x1 + (int) H, (y2 + y1) / 2);
56 list.add(new Shape(x1, y1, x2, y2, width, color, type, i, dm, text));
57 list.add(new Shape(x1, y1, x1 + (int) H, (y2 + y1) / 2, width, color, type, i, dm, text));
58 list.add(new Shape(x2, y2, x1 + (int) H, (y2 + y1) / 2, width, color, type, i, dm, text));
59 } else if (y1 == y2) {
60 g.drawLine(x1, y1, x2, y2);
61 g.drawLine(x1, y1, (x1 + x2) / 2, y1 + (int) H);
62 g.drawLine(x2, y2, (x1 + x2) / 2, y1 + (int) H);
63 list.add(new Shape(x1, y1, x2, y2, width, color, type, i, dm, text));
64 list.add(new Shape(x1, y1, x1 + (x1 + x2) / 2, y1 + (int) H, width, color, type, i, dm, text));
65 list.add(new Shape(x2, y2, x1 + (x1 + x2) / 2, y1 + (int) H, width, color, type, i, dm, text));
66 } else {
67 double a = Math.atan((double) (x2 - x1) / (double) (y2 - y1));
68 double x3 = (double) (x1 + x2) / 2 + H * Math.cos(a);
69 double y3 = (double) (y1 + y2) / 2 - H * Math.sin(a);
70 g.drawLine(x1, y1, x2, y2);
71 g.drawLine(x1, y1, (int) x3, (int) y3);
72 g.drawLine(x2, y2, (int) x3, (int) y3);
73 list.add(new Shape(x1, y1, x2, y2, width, color, type, i, dm, text));
74 list.add(new Shape(x1, y1, x1 + (int) x3, (int) y3, width, color, type, i, dm, text));
75 list.add(new Shape(x2, y2, (int) x3, (int) y3, width, color, type, i, dm, text));
76 }
77 } else if (type.equals("Polygon")) {
78 if (num == 0) {
79 g.drawLine(x1, y1, x2, y2);
80 list.add(new Shape(x1, y1, x2, y2, width, color, type, i, dm, text));
81 x5 = x2;
82 y5 = y2;
83 }
84 num++;
85 if (num == 1) {
86 x3 = x1;
87 y3 = y1;
88 }
89 if (x2 == x4 && y2 == y4) {
90 g.drawLine(x1, y1, x3, y3);
91 list.add(new Shape(x1, y1, x3, y3, width, color, type, i, dm, text));
92 num = 0;
93 } else {
94 g.drawLine(x2, y2, x5, y5);
95 list.add(new Shape(x2, y2, x5, y5, width, color, type, i, dm, text));
96 x5 = x2;
97 y5 = y2;
98 }
99 } else {
100 Shape s = new Shape(x1, y1, x2, y2, width, color, type, i, dm, text);
101 s.draw(g);
102 list.add(s);
103 }
104 }
105
106 public void mouseDragged(MouseEvent e) {
107 if (type.equals("Pencil")) {
108 x2 = e.getX() + 7;//这里的+7 +183 是调出来的,能够使画的图是沿着鼠标
109 y2 = e.getY() + 183;
110 if (y2 < 183)
111 y2 = 183;
112 Shape s = new Shape(x1, y1, x2, y2, width, color, type, i, dm, text);
113 s.draw(g);
114 list.add(s);
115 x1 = x2;
116 y1 = y2;
117 } else if (type.equals("Erase")) {
118 x2 = e.getX() + 7;
119 y2 = e.getY() + 183;
120 if (y2 < 183)
121 y2 = 183;
122 Shape s = new Shape(x1, y1, x2, y2, width, Color.WHITE, type, i, dm, text);
123 s.draw(g);
124 list.add(s);
125 x1 = x2;
126 y1 = y2;
127 } else if (type.equals("喷枪")) // 难点
128 {
129 Random rand = new Random();// 实例化一个随机数类的对象
130 int size = rand.nextInt(50);// 随机决定要画的点数
131 x2 = e.getX() + 7;
132 y2 = e.getY() + 183;
133 for (int j = 0; j < size; j++) {
134 // 在0-7之间可以取50次
135 int x = rand.nextInt(10);
136 int y = rand.nextInt(10);
137 // 不断改变(x1,y1)的坐标值,实现在(x1,y1)的周围画点
138 Shape s = new Shape(x2 + x, y2 + y, x2 + x, y2 + y, width, color, type, i, dm, text);
139 s.draw(g);
140 list.add(s);
141 x1 = x2;
142 y1 = y2;
143 }
144 }
145 }
仔细看看代码,你也许注意到了,我在画图时创建了一个Shape对象,并且还把Shape对象存到了一个List中,为什么要这么做?你们可以去别人的博客上贴一个粗略实现的画图板代码,画几条直线然后再改变窗体的大小试试看,是不是画的直线不见了?那要怎么做才能使这些图形保存下来呢?这就需要用到重绘了。
但是,我们需要知道,为什么图形会消失?其实计算机中的界面什么都是画出来的。自然组件也是画出来的,而改变组件大小的时候,原来的组件无法满足现在组件的显示要求,所以组件要重新画一次,然而此时组件上的图形并不会重新再画一次,为什么?组件已经默认有重绘的方法了paint(Graphics g),所以我们需要重写这个方法,但是我们怎么能让计算机知道之前画了什么呢?这是就需要把每次画的内容记录到队列或数组中,重绘时就可以根据这个队列或是数组进行了。而创建Shape对象自然是为了方便保存这些图形的数据了。
下面是Shape的写法
1 public class Shape {
2
3 private int x1, y1, x2, y2, width;
4 private Color color;
5 private String type;
6 private ImageIcon i;
7 private DrawMain dm;
8 private JTextField text;
9
10 public Shape(int x1, int y1, int x2, int y2, int width, Color color, String type, ImageIcon i, DrawMain dm,
11 JTextField text) {
12 this.x1 = x1;
13 this.y1 = y1;
14 this.x2 = x2;
15 this.y2 = y2;
16 this.width = width;
17 this.color = color;
18 this.type = type;
19 this.i = i;
20 this.dm = dm;
21 this.text = text;
22 }
23
24
25 public void draw(Graphics2D g) {
26 g.setColor(color);
27 g.setStroke(new BasicStroke(width));
28 if (type.equals("Line") || type.equals("Pencil") || type.equals("iso_Tri") || type.equals("Polygon")
29 || type.equals("Erase") || type.equals("喷枪")) {
30 g.drawLine(x1, y1, x2, y2);
31 } else if (type.equals("Oval")) {
32 g.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1));
33 } else if (type.equals("Rect")) {
34 g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1));
35 } else if (type.equals("RoundRect")) {
36 g.drawRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1),
37 Math.abs(x2 - x1) / 3, Math.abs(y2 - y1) / 3);
38 } else if (type.equals("fill3DRect")) {
39 g.fill3DRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1), true);
40 } else if (type.equals("fillArc")) {
41 double r = ((x2 - x1) * (x2 - x1) + y1 * y1) / (2 * y1);
42 double m = Math.asin((double) (x2 - x1) / r);
43 g.fillArc(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), (int) r, 0, (int) (m * 180 / Math.PI));
44 } else if (type.equals("Image")) {
45 g.drawImage(i.getImage(), Math.min(x1, x2), Math.min(y1, y2), Math.abs(x2 - x1), Math.abs(y2 - y1), dm);
46 } else if (type.equals("Text")) {
47 g.drawString(text.getText(), x1, y1);
48 }
49 }
50
51 }
现在还有一个问题,paint该写在哪?写在之前写的DrawMain中
private List<Shape> list = new ArrayList<Shape>();
public void paint(Graphics gr) {
super.paint(gr);
Graphics2D g = (Graphics2D) gr;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (int i = 0; i < list.size(); i++) {
Shape shape = list.get(i);
shape.draw(g);
}
}
提醒一下:别忘了把事件监听添加到组件中!!!!
这样一来,我们的画图板就能完美使用了。当然这个画图板跟系统中的比起来还是差了很多了,比如撤销、重做、保存等功能都还不具备,剩下的功能就需要后面慢慢研究再完善了。