简单画图板

 整体思路的分析:1,首先要有一个得到窗体的类,即包含主函数的类2,当点击鼠标时,要发生鼠标事件,所以要写一个监听类。3,当画不同的图形时,要写成不同的类,来实现画图形的方法。4,当我们前三步做好时,每当我们点击鼠标时,能够画图形了,但当我们把窗体移动时,原来画的图形就不见了,这样,我们就必须要实现图形的重绘,我们定义一个队列用来保存图形,所以就必须要有一个队列类5,虽然能够实现画板的重绘,但有时我们希望把图形保存到硬盘里。所以就必须要有一个打开和保存文件的类。

具体步骤:

1,得到窗体的类,由于这个类比较简单,我就不完全把代码写下来了。

javax.swing.JRadioButton line = new javax.swing.JRadioButton("Line");
		line.setActionCommand("Line");
		line.setSelected(true);// 默认选中

		javax.swing.JRadioButton rect = new javax.swing.JRadioButton("Rect");
		rect.setActionCommand("Rect");

		javax.swing.JRadioButton oval = new javax.swing.JRadioButton("Oval");
		oval.setActionCommand("Oval");
		
		javax.swing.JRadioButton filloval = new javax.swing.JRadioButton("FillOval");
		filloval.setActionCommand("Filloval");
		
		javax.swing.JRadioButton trangle = new javax.swing.JRadioButton("Trangle");
		trangle.setActionCommand("Trangle");
		
		javax.swing.JButton bu_color=new javax.swing.JButton("ChooseColor");
		final javax.swing.JButton b=new javax.swing.JButton("Save");
		final javax.swing.JButton c=new javax.swing.JButton("Open");

 这是窗体的组件。"ChooseColor"按钮是选择颜色按钮,"Save"是图形保存到文件的按钮,"Open"是将文件的图形显示出来的按钮。为了窗体的美观,我还定义了两个面板。

//给窗体加面板
		Panel panel=new Panel();
		Panel panel2=new Panel();
		//将按钮添加到面板中去
		panel.add(bu_color);
		panel.add(line);
		panel.add(rect);
		panel.add(oval);
		panel.add(filloval);
		panel.add(trangle);
		panel2.add(b);
		panel2.add(c);
		//将面板添加到窗体中去
		this.add(panel,BorderLayout.NORTH);
		panel.setBackground(Color.LIGHT_GRAY);
		this.add(panel2,BorderLayout.SOUTH);
		panel2.setBackground(Color.LIGHT_GRAY);
        

 简单的界面已经完成了。效果如下:



 

2.然后我们需要写画不同形状的类,由于我的画图板是写了六种不同形状,我在这里主要写一下画矩形和画三角形的类。画矩形的方法:

public class Rect extends Shape{
	
	public int x1,y1,x2,y2;
	
	public Rect(int x1,int y1,int x2,int y2 ){
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
	}
	
	public void draw(Graphics g){
		 type=2;//标记类型的变量
		g.setColor(this.getColor());
		if(x1<x2&&y1<y2)
			g.drawRect( x1, y1, Math.abs(x1-x2), Math.abs(y1-y2));
		else if(x1>x2&&y1>y2)
			g.drawRect(x2, y2, Math.abs(x1-x2), Math.abs(y1-y2));
		else if(x1>x2&&y1<y2)
			g.drawRect(x2, y1, Math.abs(x1-x2), Math.abs(y1-y2));
		else 
			g.drawRect(x1, y2, Math.abs(x1-y1), Math.abs(y1-y2));
	}

}

 画三角形的类:

public class Trangle extends Shape {
	public int x1,y1,x2,y2;
	Random random=new Random();
	//随机生成一点的坐标
	int x3=random.nextInt(250)+50;
	int y3=random.nextInt(250)+50;
	public Trangle (int x1,int y1,int x2,int y2){
		this.x1=x1;
		this.y1=y1;
		this.x2=x2;
		this.y2=y2;
	}
	public void draw(Graphics g){
		type=5;
		g.setColor(this.getColor());
		int d1=(int)Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
		int d2=(int)Math.sqrt((x1-x3)*(x1-x3)+(y1-y3)*(y1-y3));
		int d3=(int)Math.sqrt((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3));
		if((d1+d2)>d3&&(d1+d3)>d2&&(d2+d3)>d1){
			g.drawLine(x1,y1,x2,y2);
			g.drawLine(x1,y1,x3,y3);
			g.drawLine(x2, y2, x3, y3);
		}
	}

}

 这样画图形的类就已经完成了。然后我们就应当要画图形了,画图形首先必须要有监听器,能够监听事件源

3.监听类

public class DrawListener implements java.awt.event.MouseListener {

	private int x1,y1,x2,y2;
	private Graphics g;
	private javax.swing.ButtonGroup group;
	private Color color = Color.BLACK;
	Shape sh=null;
	
	//传参过来
	public DrawListener(Graphics g,javax.swing.ButtonGroup group){
		this.g = g;
		this.group = group;
	}
	public void setColor(Color color) {
		this.color = color;
	}

	public void mousePressed(MouseEvent e) {
		x1 = e.getX();
		y1 = e.getY();
	}

	public void mouseReleased(MouseEvent e) {
		x2 = e.getX();
		y2 = e.getY();
		
		//得到选中的形状
		String str = group.getSelection().getActionCommand();
		
		Shape sh=null;
		//设置形状的颜色
		
		if("Line".equals(str)){
			 sh = new Line(x1,y1,x2,y2);
		}
		if("Rect".equals(str)){
			sh = new Rect(x1,y1,x2,y2);
		}
		if("Oval".equals(str)){
			sh=new Oval(x1,y1,x2,y2);
		}
		if("Filloval".equals(str)){
			sh=new fillOval(x1,y1,x2,y2);
		}

 

这只是监听图形选择按钮,还有颜色选择按钮和打开,保存按钮也要添加监听器,只不过这三种按钮加的不是鼠标监听器,而是事件监听器。我首先只写下颜色选择按钮监听器,保存和打开按钮到后面再写,应为牵涉到文件的读写。

颜色选择按钮添加事件监听器:

bu_color.addActionListener(new java.awt.event.ActionListener(){
			public void actionPerformed(ActionEvent e){
				showColorSelecter();
			}
		});


public void showColorSelecter(){
		this.color=JColorChooser.showDialog(null, "请选择颜色", java.awt.Color.black);
		//System.out.println(color);
		//DrawListener l=new DrawListener(color);
		lis.setColor(color);
	}

 当我们到这一步时,我们已经可以选择不同的颜色来画不同的形状了,但我们又发现,当我们移动窗体时,我们画过的图形又不见了,所以我们必须要实现画板的重绘。所以必须再写一个类,然后在定义一个泛型的队列,将画过的图形保存到队列中。而且写的这个类是用来保存不同形状的类,所以不同形状的类必须要继承该类。

画图行时的效果如下:



 

4.形状(用来保存不同图形)类

public abstract class Shape {
	
	public  Color c;//颜色
	public int type;
	
	
	public void setColor(Color c){
		this.c = c;
	}
	
	public Color getColor(){
		return c;
	}
	/**
	 * 绘制的方法
	 * @param g
	 */
	public abstract void draw(Graphics g);

}

 

现在我们已经能够实现画图板的重绘了,但我们有时还想把它保存到硬盘里,所以我们必须再写一个类,这个类是用来把图形保存到文件中,而且在把文件中的图形显示出来

5.文件读写类:

public class FileReadAndWrite {

	/**
	 * 将画图板写到文件中去
	 * 
	 * @param path写入的路径
	 * @param shape待写的数据
	 */

	public static void WriteFile(String path, NJListImp<Shape> shapes) {
		File file = new File(path);// 先创建一个文件
		try {
			// 定义一个输出流
			FileOutputStream fos = new FileOutputStream(file);
			DataOutputStream dos = new DataOutputStream(fos);
			// 得到总的数据
			int t = shapes.size();
			// 写入文件头
			dos.writeInt(t);
			// 遍历队列
			for (int i = 0; i < shapes.size(); i++) {
				Shape shape = shapes.get(i);// 根据下标取对象
				// 得到对象的颜色
				// System.out.println(shape);
				// System.out.println(shape.getColor());
				Color color = shape.getColor();
				int c = color.getRGB();
				// 将颜色写入到文件中
				dos.writeInt(c);
				dos.writeByte(shape.type);// 将对象的类型写入到文件中去
				if (shape.type == 1) {// 如果是直线
					// 强制转化
					Line line = (Line) shape;
					// 将4个点写到文件中去
					dos.writeInt(line.x1);
					dos.writeInt(line.y1);
					dos.writeInt(line.x2);
					dos.writeInt(line.y2);

				}
				if (shape.type == 2) {// 如果是矩形
					// 强制转化
					Rect rect = (Rect) shape;
					// 将4个点写到文件中去
					dos.writeInt(rect.x1);
					dos.writeInt(rect.y1);
					dos.writeInt(rect.x2);
					dos.writeInt(rect.y2);
				}
				if (shape.type == 3) {// 如果是圆形
					// 强制转化
					Oval oval = (Oval) shape;
					// 将4个点写到文件中去
					dos.writeInt(oval.x1);
					dos.writeInt(oval.y1);
					dos.writeInt(oval.x2);
					dos.writeInt(oval.y2);
				}
				
				if (shape.type == 4) {// 如果是圆形
					// 强制转化
					fillOval filloval = (fillOval) shape;
					// 将4个点写到文件中去
					dos.writeInt(filloval.x1);
					dos.writeInt(filloval.y1);
					dos.writeInt(filloval.x2);
					dos.writeInt(filloval.y2);
				}

				if (shape.type == 5) {// 如果是三角形
					// 强制转化
					Trangle trangle = (Trangle) shape;
					// 将4个点写到文件中去
					dos.writeInt(trangle.x1);
					dos.writeInt(trangle.y1);
					dos.writeInt(trangle.x2);
					dos.writeInt(trangle.y2);
					dos.writeInt(trangle.x3);
					dos.writeInt(trangle.y3);
				}
				
			}
			dos.flush();
			dos.close();
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 将文件中的数据读出来
	 * 
	 * @param path待读的路径
	 * @return:返回读出队列
	 */
	public static NJListImp<Shape> ReadFile(String path) {
		NJListImp<Shape> shape = new NJListImp<Shape>();
		try {
			// 定义输入流
			FileInputStream fis = new FileInputStream(path);
			DataInputStream dis = new DataInputStream(fis);
			// 得到队列中数据的总长度
			int len = dis.readInt();
			// 根据队列的长度依次读出数据
			for (int i = 0; i < len; i++) {
				int c = dis.readInt();
				Color color = new Color(c);// 读出颜色
				Byte b = dis.readByte();// 读出类型
				if (b == 1) {
					// 读出两个点的坐标
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();
					// 将数据加到shape中
					Line line = new Line(x1, y1, x2, y2);
					line.setColor(color);
					line.type = b;
					shape.add(line);
				}
				if (b == 2) {
					// 读出两个点的坐标
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();
					// 将数据加到shape中
					Rect rect = new Rect(x1, y1, x2, y2);
					rect.setColor(color);
					rect.type = b;
					shape.add(rect);
				}
				if (b == 3) {
					// 读出两个点的坐标
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();
					// 将数据加到shape中
					Oval oval = new Oval(x1, y1, x2, y2);
					oval.setColor(color);
					oval.type = b;
					shape.add(oval);
				}
				if (b == 4) {
					// 读出两个点的坐标
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();
					// 将数据加到shape中
					fillOval filloval = new fillOval(x1, y1, x2, y2);
					filloval.setColor(color);
					filloval.type = b;
					shape.add(filloval);
				}
				if (b == 5) {
					// 读出三个点的坐标
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();
					int x3=dis.readInt();
					int y3=dis.readInt();
					
					// 将数据加到shape中
					Trangle trangle = new Trangle(x1, y1, x2, y2);
					trangle.setColor(color);
					trangle.type = b;
					trangle.x3=x3;
					trangle.y3=y3;
					shape.add(trangle);
				}
			}
			dis.close();
			fis.close();
			return shape;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}

 当写到这来时,我们在给"Save"和"Open"按钮添加监听器:

由于我这步操作是基于已经写好的程序后添加的功能,故我们写个事件匿名类,就不需修改前面的代码

//给保存和打开按钮添加事件监听器
		ActionListener ac=new ActionListener (){
			public void actionPerformed(ActionEvent e){
				if(e.getSource()==b)
				FileReadAndWrite.WriteFile(path, shapes);
				else if(e.getSource()==c){
				shapes=FileReadAndWrite.ReadFile(path);
				repaint();
				}
			}
		};
		b.addActionListener(ac);
		c.addActionListener(ac);
		//设置按钮的事件监听器

 如果我重新选择窗体的颜色,或是撤销上次画过的图形运行效果如下:



 

这个简单的画图板就已经完成了

在这个基础上,我又添加了一些功能,比如说背景颜色的选择,清除最后一次画的图形,和清除所有的图形

 我在这个程序中的给画布设置颜色选择器时,做了很久,当点击画布颜色选择按钮时,不知道怎么把颜色传到画布中去,后来想了个笨方法,用构造器传参。后来由于老师指导,直接在监听器中写个setcolor方法就可以在选择颜色的那个方法直接通过类名去调用了,以前学的基础内容,我就不知道用在这里了。还有我在写清除最后一次画过图形的方法时,没有想到调用队列中的remove方法,直接通过移除最后的对象就可以了。我是自己把最后的对象中的数据全部设为0的,我觉得我以后思维要开拓点,应充分使用API文档中的方法,最后还有个问题就是,在往窗体中加组件时,必须把加组件的程序代码写在this.setVisible(true)前面,不然,有时运行程序时,添加的组件将不会出现在窗体中。而this.setVisible(true)必须写在得多画布代码的前面,否则将会出现空指针异常。

但我背景颜色选择中还有个问题:当把画过的图形及窗体颜色及画布颜色保存到文件中,然后在点击打开按钮时,画过的图形不见了,只有窗体的颜色,然后最小化窗体,然后在打开,窗体上的图形又出现了。我觉得很奇怪,弄了很久都没弄出来,哪个高手指点一下啊

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值