java中画图板的基本实现

1.首先是通过JFrame写一个画图面板的界面。

           (1)需要给界面添加一个监听器,用来获取鼠标按下和释放时候的坐标。这个不能使用动作监听器(ActionListener),只有使用鼠标监听器(MouseListener)才能够获取到坐标。

                ActionListener:可以给需要关注其动作的组件(如Button)添加监听器(addActionListener(this);),之后在事件处理方法(public void actionPerformed(ActionEvent event){})中,对每个事件进行不同处理。

                MouseListener:用于接收组件上“感兴趣”的鼠标事件(按下、释放、单击、进入或离开)的侦听器接口。(要跟踪鼠标移动和鼠标拖动,请使用 MouseMotionListener。)旨在处理鼠标事件的类要么实现此接口(及其包含的所有方法),要么扩展抽象类 MouseAdapter(仅重写所需的方法)。

            (2)为了绘制出一个形状,我们还需要获取绘制权限获取画笔对象,这个权限在java中叫做Graphics对象,或者叫画布对象。我们可以从窗体上获取这个对象,然后创建一个鼠标监听器对象,把画布对象传给监听器。最后给窗体就加上鼠标监听器对象,这样我们在窗体上按下和释放鼠标的时候,就会获取到这两个位置的坐标。最后调用画布对象绘制的方法(对象.drawline())

<textarea readonly="readonly" name="code" class="java">
package com.xml.study0708;

import java.awt.Color;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;

import javax.swing.JButton;
import javax.swing.JFrame;

public class DrawFrame extends JFrame { // 继承JFrame,重写paint重绘方法

	private Shape[] shapeArray = new Shape[1000000];// 主函数创建数组,后面要使用数组

	public static void main(String[] args) {
		DrawFrame dw = new DrawFrame();
		dw.showUI();// TODO Auto-generated method stub
	}

	public void showUI() {
		this.getContentPane().setBackground(Color.BLACK);// 设置画图面板的背景颜色getcontentpane()
		this.setTitle("画图面板");// 设置标题
		this.setSize(800, 800);// 设置窗体大小
		this.setDefaultCloseOperation(3);// 设置窗体关闭时程序退出,括号内数值3为全部关闭,或2为单个关闭退出,0或1为隐藏
		this.setLocationRelativeTo(null);// 设置窗体居中显示

		FlowLayout f1 = new FlowLayout();//流式布局管理器
		this.setLayout(f1);
                //数组创建图形按钮以及颜色按钮
		String[] jb = { "直线", "矩形", "椭圆", "三角形", "多边形", "实心圆", "动圆", "随机", "迭代分形1", "迭代分形2", "迭代分形3", "迭代分形4", "曲线",
				"橡皮擦" };
		Color[] co = { Color.RED, Color.BLUE, Color.magenta, Color.YELLOW, Color.GREEN };

		DrawMouse dr = new DrawMouse();// 创建对象用来实现监听
                //设置图形按钮以及颜色按钮
		JButton jbu[] = new JButton[14];
		for (int i = 0; i < jbu.length; i++) {
			jbu[i] = new JButton(jb[i]);
			this.add(jbu[i]);
			jbu[i].addActionListener(dr);// 添加动作监听器
			if (i > 12) {
				jbu[i].addMouseMotionListener(dr);// 添加鼠标拖动监听器
			}
		}
		JButton color[] = new JButton[5];
		for (int i = 0; i < color.length; i++) {
			color[i] = new JButton();
			color[i].setBackground(co[i]);
			color[i].setPreferredSize(new Dimension(30, 30));
			this.add(color[i]);
			color[i].addActionListener(dr);// 动作监听器

		}

		// 设置在画笔之前,窗体可视化组件之后。设置窗体可见
		this.setVisible(true);



        /**1、图形画在哪个图形上,那么画笔组件就在这个图形上获取

           2、获取画笔对象,一定在窗体可见之后

           3、获取的画笔对象必须要用一个方法来传给自己定义的事件监听类中
        */
		Graphics g = this.getGraphics();// 从窗体上获取画布对象,即获取窗体在屏幕上占据的区域,这块区域是可以改变颜色的
                dr.setGraphics(g);//传入画布对象
		/**
		 * 1.找到事件源 2.确定监听器方法 3.绑定事件处理的类 格式:1.2(3);
		 */
		// DrawMouse dr = new DrawMouse();// 创建对象用来实现监听
		this.addMouseListener(dr);// 给窗体添加鼠标监听器
		this.addMouseMotionListener(dr);// 给窗体添加鼠标拖动监听器

                dr.setShapeArray(shapeArray);// 传递数组对象

	}

	// 绘制组件重写方法
	public void paint(Graphics gr) {// 继承的JFrame的方法
		super.paint(gr);//super指父类
		System.out.println("重绘!");
		for (int i = 0; i < shapeArray.length; i++) {
			Shape shape = shapeArray[i];
			if (shape != null) {//如果赋值出的数组不是空的
				shape.drawshape(gr);
			} else {//如果赋值出的数组是空的
				break;
			}
		}
	}
	// 取出shapeArray数组中保存的图形对象,绘制

}</textarea>

2.重新定义一个类,即事件处理类(如DrawMouse),继承接口MouseListener, ActionListener,MouseMotionListener。

              (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

扫描二维码关注公众号,回复: 2553395 查看本文章

                  简而言之:用e.getSource()得到的是jbt,而用e.getActionCommand()得到的是button。

<textarea readonly="readonly" name="code" class="java">
	public void actionPerformed(ActionEvent e) {
		if ("".equals(e.getActionCommand())) {
			JButton JBu = (JButton) e.getSource();// 获取事件源。强制转换,父类转换成子类,
			Color color = JBu.getBackground();// 获取背景色
			gr.setColor(color);// 设置画笔颜色
		} else {
			name = e.getActionCommand();
			System.out.println("name=" + name);// 输出语句测试监听按钮是否完成
		}

	}</textarea>

               (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);
		}
    }

3.重绘

              在创建窗体时我们已经定义了窗体的大小,如果我们再次改变窗体大小的时候,原来的窗体就不满足显示的需求。这时候就会将窗体上所有的组件再重新绘制一次,自动调用了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;
		}
	}

猜你喜欢

转载自blog.csdn.net/weixin_42621338/article/details/81065258
今日推荐