(1)需要给界面添加一个监听器,用来获取鼠标按下和释放时候的坐标。这个不能使用动作监听器(ActionListener),只有使用鼠标监听器(MouseListener)才能够获取到坐标。
ActionListener:可以给需要关注其动作的组件(如Button)添加监听器(addActionListener(this);),之后在事件处理方法(public void actionPerformed(ActionEvent event){})中,对每个事件进行不同处理。
MouseListener:用于接收组件上“感兴趣”的鼠标事件(按下、释放、单击、进入或离开)的侦听器接口。(要跟踪鼠标移动和鼠标拖动,请使用 MouseMotionListener
。)旨在处理鼠标事件的类要么实现此接口(及其包含的所有方法),要么扩展抽象类 MouseAdapter
(仅重写所需的方法)。
(2)为了绘制出一个形状,我们还需要获取绘制权限获取画笔对象,这个权限在java中叫做Graphics对象,或者叫画布对象。我们可以从窗体上获取这个对象,然后创建一个鼠标监听器对象,把画布对象传给监听器。最后给窗体就加上鼠标监听器对象,这样我们在窗体上按下和释放鼠标的时候,就会获取到这两个位置的坐标。最后调用画布对象绘制的方法(对象.drawline())
(1)首先实例化一个Graphics对象来接受传过来的画笔对象。
private Graphics gr;//创建画笔
public void setGraphics(Graphics g) { // 创建对象,初始化
gr = g;
}
(2)由于使用的是字符串数组来储存画图按钮上面的字符串(即图形名字),以及Color类的数组储存按钮的背景颜色,所以在重写ActionListener接口中的actionPerformed方法时,要首先获取按钮上的颜色或者文字,当获取的不是文字时,说明点击的是颜色按钮,读取按钮的颜色后给设置画笔的颜色;如果读取的是文字时,需要继续下一步的操作,实现代码如下:
e.getSource()方法依赖于事件对象。
比如:JButton jbt = new JButton("直线");中事件对象就是jbt
e.getActionCommand()方法依赖于按钮上的字符串
比如:JButton jbt = new JButton("直线");中字符串button
简而言之:用e.getSource()得到的是jbt,而用e.getActionCommand()得到的是button。
(3)重写实现其他继承的方法
java中有许多绘制图形的方法,画图需要获取一定数量的坐标值x,y。在继承的接口的方法中有MouseEvent类型的形参e,可以通过形参调用getx(),gety()来获取经过某种操作(如点击,释放,单击)过后当前位置的x坐标以及y坐标。
用画笔的实例化对象调用drawline(x1,y1,x2,y2)方法可以画一条直线
public void mousePressed(MouseEvent e) {
System.out.println("按下");
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e) {
System.out.println("释放");
x2 = e.getX();
y2 = e.getY();
if (name.equals("直线")) {
gr.drawLine(x1, y1, x2, y2);
}
if (name.equals("椭圆")) {
gr.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
}
}
使用画笔对象gr调用drawRext()的方法画矩形(圆形同理,圆形是通过绘制矩形的方法绘制内切圆形)。需要注意的是坐标(x1,y1)代表的是矩形左上角的点,即x1,y1均是最小值。因此需要math类取大小值,绝对值。
由于java中没有定义画三角形的函数,所以需要通过一个变量的操作来控制花三条直线的方法来实现。多边形同理
private int count = 1;
public void mouseClicked(MouseEvent e) {
System.out.println("单击");
if (name.equals("三角形") && count == 2) {
x3 = e.getX();
y3 = e.getY();
gr.drawLine(x2, y2, x3, y3);
if (e.getClickCount() == 2) {
gr.drawLine(x1, y1, x3, y3);
count = 1;
}
}
public void mousePressed(MouseEvent e) {
System.out.println("按下");
if (count == 1) {
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e) {
System.out.println("释放");
if (count == 1) {
x2 = e.getX();
y2 = e.getY();
if (name.equals("三角形") && count == 1) {
gr.drawLine(x1, y1, x2, y2);
}
}
在创建窗体时我们已经定义了窗体的大小,如果我们再次改变窗体大小的时候,原来的窗体就不满足显示的需求。这时候就会将窗体上所有的组件再重新绘制一次,自动调用了paint方法,这个方法是定义在JFrame和JPanel中都有的。因此必须让窗体类继承JFrame类或者JPanel类,再重写paint()方法。
但是由于可能改变窗体大小之前已经绘制了不少图形,会有较多坐标需要保存重绘,所以需要新建一个对象数组用来存储数据,然后再重写的paint方法中直接获取使用。
(1) 首先创建一个用来保存图形数据的shape类,新建数组对象。
/**
* 创建图形对象时初始化该图形的数据
*/
public Shape(int x1, int y1, int x2, int y2, String name, Color color) {
if (name.equals("直线") || name.equals("矩形") || name.equals("椭圆")) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.name = name;
this.color = color;
}
}
}
(2)在事件处理类DrawMouse中创建数组对象和数组角标index。每画出一个图形保存在数组中一次。由于点,三角形,多边形,曲线,橡皮擦,迭代图形都是通过两点绘制即drawline(),保存在直线重绘即可。
private Shape[] shapeArray;
private int index = 0;// 创建数组角标
public void setShapeArray(Shape[] shapeArray) {//实例化数组
this.shapeArray = shapeArray;
}
if (name.equals("直线")) {
gr.drawLine(x1, y1, x2, y2);
Shape shape = new Shape(x1, y1, x2, y2, "直线", gr.getColor());// 创建shape对象用来保存绘制图形的数据
shapeArray[index] = shape;
index++;
}
if (name.equals("矩形")) {
gr.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
Shape shape = new Shape(x1, y1, x2, y2, "矩形", gr.getColor());
shapeArray[index] = shape;
index++;
}
(3)三角形和多边形的绘制是由多条直线绘制,所以每画出一条直线保存一次数据到数组中。
第一次点击的时候
if (name.equals("三角形") && count == 1) {
gr.drawLine(x1, y1, x2, y2);
Shape shape = new Shape(x1, y1, x2, y2, "直线", gr.getColor());
shapeArray[index] = shape;
index++;
count++;
}
第二次点击的时候
if (name.equals("三角形") && count == 2) {
x3 = e.getX();
y3 = e.getY();
gr.drawLine(x2, y2, x3, y3);
Shape shape = new Shape(x2, y2, x3, y3, "直线", gr.getColor());
shapeArray[index] = shape;
index++;
if (e.getClickCount() == 2) {
gr.drawLine(x1, y1, x3, y3);
Shape shape1 = new Shape(x1, y1, x3, y3, "直线", gr.getColor());
shapeArray[index] = shape1;
index++;
count = 1;
}
}
多边形count == 2(即第二次点击)或者双击闭合图形的时候
if (name.equals("多边形") && count == 2) {
x3 = e.getX();
y3 = e.getY();
gr.drawLine(x2, y2, x3, y3);
Shape shape = new Shape(x2, y2, x3, y3, "直线", gr.getColor());
shapeArray[index] = shape;
index++;
x2 = x3;
y2 = y3;
System.out.println("画一条线");
if (e.getClickCount() == 2) {
gr.drawLine(x1, y1, x3, y3);
Shape shape1 = new Shape(x1, y1, x3, y3, "直线", gr.getColor());
shapeArray[index] = shape1;
index++;
System.out.println("最后连接");
count = 1;
}
}
(4)数据全部保存到数组中以后在界面类中继承JFrame或者JPanel,重写paint方法。
首先在界面类中调用事件处理类DrawMouse中的setShapeArray方法 ,将方法传递给界面类中的数组对象。
dr.setShapeArray(shapeArray);
super指父类中。this指本类中。
// 绘制组件重写方法
public void paint(Graphics gr) {
super.paint(gr); //调用父类中的方法
System.out.println("重绘!");
for (int i = 0; i < shapeArray.length; i++) {
Shape shape = shapeArray[i]; //将数组赋值给shape对象
if (shape != null) { //如果数组不是空的
shape.drawshape(gr); //调用shape类中的方法drawshape
} else {
break;
}
}
}
// 取出shapeArray数组中保存的图形对象,绘制
(5)shape类中的重绘方法
// 根据图形名字绘制对应的图形
public void drawshape(Graphics gr) {
switch (name) {
case "直线":
gr.setColor(color);
gr.drawLine(x1, y1, x2, y2);
break;
case "矩形":
gr.setColor(color);
gr.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
break;
case "椭圆":
gr.setColor(color);
gr.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
break;
case"橡皮擦":
gr.setColor(color);
gr.fillRect(x1, y1, 50, 50);
break;
}
}