java入门之 画板及画板重绘(详细版)

关于画板和画板重绘

效果图如下(完整代码请看文末):

为什么要重绘

在Java中,Swing组件是由开发人员编写好的,所有我们看得见的组件(包括窗体)都是画出来的,当我们改动窗体的大小时,即重新调动了paint方法,也就是重新绘制了一个窗体。因此要想实现重绘功能,我们需要将原先在窗体/面板中的所绘制的图形保存起来,当改动窗体大小时,重新调用paint方法,并且同时将原先保存(绘制的)图形绘制出来,这样就完成了重绘功能。

具体步骤及思路

<1> 创建画板实现图形的正常绘制

1、创建窗口对象,创建面板。

        DrawUI jf = new DrawUI();
		// 设置窗体属性
		jf.setTitle("画图工具");
		jf.setSize(1000, 1000);
		jf.setLocationRelativeTo(null);
		jf.setDefaultCloseOperation(3);

		// 创建面板1(放按钮)
		JPanel jp = new JPanel();
		jp.setBackground(Color.LIGHT_GRAY);
		jp.setPreferredSize(new Dimension(0, 80));
		jf.add(jp,BorderLayout.NORTH);
		//创建面板(画板)
		DrawPanel drawPanel=new DrawPanel();
		drawPanel.setBackground(Color.WHITE);
		jf.add(drawPanel,BorderLayout.CENTER);
         // 设置可见(画笔必须在其后面)
		jf.setVisible(true);

2、利用数组添加按钮(方便后续修改)

        //形状按钮
		String[] name = { "曲线","直线", "椭圆", "矩形" ,"三角形","三点分形"};
		for (int i = 0; i < name.length; i++) {
			JButton button = new JButton(name[i]);
			button.setBackground(Color.cyan);
			button.setBounds(30, 30, 100, 30);
			jp.add(button);
        //颜色按钮
		Color[] color = {Color.red,Color.green,Color.blue};
		for(int col = 0;col<color.length;col++) {
			JButton jcolor = new JButton();
			jcolor.setBackground(color[col]);
			jcolor.setBounds(30, 30, 100, 30);
			jp.add(jcolor);
			jcolor.addActionListener(mouse);//添加动作监听器
		}

3、为按钮添加监听器(监听对象动作状态变化,从而执行相关代码),根据监听事件执行相应功能(画“直线”、“曲线”、“三角形”等),即同时写下绘制不同图形的方法。并且创建数组,储存图形(为后续的画板的重绘功能做准备)

        // 创建鼠标监听器对象,窗体中添加
		DrawListener mouse = new DrawListener();

        //画板添加监听器,监听鼠标点击移动事件(绘制曲线用鼠标动作监听器)
        drawPanel.addMouseListener(mouse);
        drawPanel.addMouseMotionListener(mouse);

        //按钮添加监听器(监听鼠标按下)
		button.addActionListener(mouse);

4、为画板添加画板(注意!要在画板(面板)上作画,那么必须从画板上获取画笔)

画笔是java中有的,直接获得就可以使用

        // 从画板中获得画笔
		Graphics g = drawPanel.getGraphics();
		// 将画笔传递过去(将上一行的Graphics类属性g赋值给监听器对象的属性
		mouse.gr = g;

5、为主界面添加主函数

	public static void main(String[] args) {
		DrawUI ui = new DrawUI();
		ui.showUI();
	}

<2> 创建接口,监听事件

1、在接口监听事件中,完善代码(图形绘制)—通过判断按钮上的文字(“直线”,“曲线”)来执行相应代码。

注意!接口使用时,需要重写接口中的所有方法,无论是否使用。

@Override
	public void mouseClicked(MouseEvent e) {

		System.out.println("鼠标点击了");
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		x1 = e.getX();
		y1 = e.getY();
		System.out.println("按下");
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		x2 = e.getX();
		y2 = e.getY();
		System.out.println("释放");

		if(name != null) {
		//创建Shapes对象,保存数据。shapes的数据类型是Shapes,保存它的也的是Shapes类型,所以创建Shapes类型数组
		Shapes shape = new Shapes(x1,y1,x2,y2,x3,y3,name,color);
		//将shape的数据保存到数组中
		shapeArr[index++] = shape;
		shape.drawShapes(gr);
		
		
	}
	}
	@Override
	public void mouseEntered(MouseEvent e) {

	}

	@Override
	public void mouseExited(MouseEvent e) {

	}

	@Override
	public void mouseDragged(MouseEvent e) {
		if ("曲线".equals(name)) {
			x = e.getX();
			y = e.getY();
			gr.drawLine(x2, y2, x, y);
			x2 = x;
			y2 = y;
			System.out.println("画曲线");
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void actionPerformed(ActionEvent e) {
		JButton jbu = (JButton) e.getSource(); // 看不懂
		Color color = jbu.getBackground();
		if (e.getActionCommand().equals("")) {
			gr.setColor(color);
		} else {
			name = e.getActionCommand();
		}
		System.out.println("String = " + name);
	}

2、三角形的绘制

    if ("三角形".equals(name)) {
			if (c == 0) {
				x1 = e.getX();
				y1 = e.getY();
				c++;
				System.out.println("第1点" + x1 + "  " + y1);
			} else if (c == 1) {
				x2 = e.getX();
				y2 = e.getY();
				gr.drawLine(x1, y1, x2, y2);
				c++;
				System.out.println("第2点" + x1 + "  " + y1 + x2 + "  " + y2);
			} else if (c == 2) {
				x3 = e.getX();
				y3 = e.getY();
				gr.drawLine(x3, y3, x2, y2);
				gr.drawLine(x3, y3, x1, y1);
				System.out.println("第3点" + x3 + "  " + y3 + x2 + "  " + y2);
			}
			System.out.println("点击" + x1 + " " + y1 + "       " + x2 + " " + y2);
		}
		System.out.println("三角形");

3、直线、矩形的绘制

if ("直线".equals(name)) {
			gr.drawLine(x1, y1, x2, y2);
		} else if ("椭圆".equals(name)) {
			if (x2 > x1) {
				gr.drawOval(x1, y1, Math.abs(x2 - x1), Math.abs(y2 - y1));
			} else {
				gr.drawOval(x2, y2, Math.abs(x1 - x2), Math.abs(y1 - y2));
			}
		} else if ("矩形".equals(name)) {
			gr.drawRect(Math.min(x1, x2), y1, Math.abs(x2 - x1), Math.abs(y2 - y1));
		} else if ("三点分形".equals(name)) {
			
		}

4、三点分形的绘制

Random random = new Random();
			int x1 = (int) (Math.random() * 500);
			int y1 = (int) (Math.random() * 500);
			int x2 = (int) (Math.random() * 500);
			int y2 = (int) (Math.random() * 500);
			int x3 = (int) (Math.random() * 500);
			int y3 = (int) (Math.random() * 500);
			int xp = (int) (Math.random() * 500);
			int yp = (int) (Math.random() * 500);
			for (int i = 0; i < 1000; i++) {
				int k = random.nextInt(3);
				if (k == 0) {
					gr.drawLine((x1 + xp) / 2, (y1 + yp) / 2, (x1 + xp) / 2, (y1 + yp) / 2);
					xp = (x1 + xp) / 2;
					yp = (y1 + yp) / 2;
				} else if (k == 1) {
					gr.drawLine((x2 + xp) / 2, (y2 + yp) / 2, (x2 + xp) / 2, (y2 + yp) / 2);
					xp = (x2 + xp) / 2;
					yp = (y2 + yp) / 2;
				} else if (k == 2) {
					gr.drawLine((x3 + xp) / 2, (y3 + yp) / 2, (x3 + xp) / 2, (y3 + yp) / 2);
					xp = (x3 + xp) / 2;
					yp = (y3 + yp) / 2;
				}
			}

实现重绘功能

1、创建重绘画板(继承原画板)——(重绘组件—保存原先所绘制的组件,重绘图形)

public class DrawPanel extends JPanel {
    //保存绘制组件的功能:调用父类的方法
	//super 表示当前的父类对象
    public void paint(Graphics g) {
        super.paint(g);
        
}

2、在重绘画板中重绘图形

                for(int i=0;i<shapeArr.length;i++) {
					Shapes shape = shapeArr[i];
					if(shape != null) {
						System.out.println("shape="+ shape);
						shape.drawShapes(g);
					}
				}

2、创建数组保存所绘制的图形,创建数组下标(方便取出)

    //定义Shapes数组,保存图形对象
	public Shapes[] shapeArr = new Shapes[1000];
	//定义操作数组的下标
	public int index=0;

实现同时绘制的功能。(当我们改变窗体时,原先所绘制的图形应与窗口改变同时发生,不能改变窗口后,再一个个显现出原先所绘制的图形)

 4、根据保存的数组(图形),还原图形(重绘)

	//根据保存的数据还原图形
	public void drawShapes(Graphics g) {
		System.out.println("drawShapes:" + name);
		switch (name) {
		case"三角形" :
			if (c == 0) {
				c++;
				System.out.println("第1点" + x1 + "  " + y1);
			} else if (c == 1) {
				gr.drawLine(x1, y1, x2, y2);
				c++;
				System.out.println("第2点" + x1 + "  " + y1 + x2 + "  " + y2);
			} else if (c == 2) {
				gr.drawLine(x3, y3, x2, y2);
				gr.drawLine(x3, y3, x1, y1);
				System.out.println("第3点" + x3 + "  " + y3 + x2 + "  " + y2);
			}
			System.out.println("点击" + x1 + " " + y1 + "       " + x2 + " " + y2);
		System.out.println("三角形");
		break;
        
                //重绘图形
				//取出数组中的数据,即遍历数组
				//用空对象调用属性或方法会出现空指针异常
				for(int i=0;i<shapeArr.length;i++) {
					Shapes shape = shapeArr[i];
					if(shape != null) {
						System.out.println("shape="+ shape);
						shape.drawShapes(g);
					}
				}

5、创建数组,将图形保存到数组中

加if判断,是为了当没有在面板上绘制图形时,改变窗体大小则不需要重绘。(不加if会报错)

		if(name != null) {
		//创建Shapes对象,保存数据。shapes的数据类型是Shapes,保存它的也的是Shapes类型,所以创建Shapes类型数组
		Shapes shape = new Shapes(x1,y1,x2,y2,x3,y3,name,color);
		//将shape的数据保存到数组中
		shapeArr[index++] = shape;
		shape.drawShapes(gr);

<3> 信息传递

1、在主界面画板上获得的画笔需要给鼠标的对象

        // 添加画笔
		Graphics g = drawPanel.getGraphics();
		// 将画笔传递过去(将上一行的Graphics类属性g赋值给监听器对象的属性
		mouse.gr = g;
    // 保存传递过来的属性
	public Graphics gr;

2、在重绘图形时

            //保存图形的数组(接收传过来的数组)
			public Shapes[] shapeArr;

完整代码:

package com.DrawBoardo921;

import java.awt.Graphics;

import javax.swing.JPanel;

public class DrawPanel extends JPanel {
	//保存图形的数组(接收传过来的数组)
			public Shapes[] shapeArr;
			
			//重写组件的paint方法
			public void paint(Graphics g) {
				//保存绘制组件的功能:调用父类的方法
				//super 表示当前的父类对象
				//paint方法会自动调用
				super.paint(g);
				
				System.out.println("panit"+g);
				//重绘图形
				//取出数组中的数据,即遍历数组
				//用空对象调用属性或方法会出现空指针异常
				for(int i=0;i<shapeArr.length;i++) {
					Shapes shape = shapeArr[i];
					if(shape != null) {
						System.out.println("shape="+ shape);
						shape.drawShapes(g);
					}
				}
			}	
}
package com.DrawBoardo921;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;

public class DrawUI {
	public void showUI() {
		RepaintDrawUI jf = new RepaintDrawUI();
		// 设置窗体属性
		jf.setTitle("画图工具");
		jf.setSize(1000, 1000);
		jf.setLocationRelativeTo(null);
		jf.setDefaultCloseOperation(3);
		
		// 创建面板
		JPanel jp = new JPanel();
		jp.setBackground(Color.LIGHT_GRAY);
		jp.setPreferredSize(new Dimension(0, 80));
		jf.add(jp,BorderLayout.NORTH);
		
		DrawPanel drawPanel=new DrawPanel();
		drawPanel.setBackground(Color.WHITE);
		jf.add(drawPanel,BorderLayout.CENTER);
		
		// 创建鼠标监听器对象,窗体中添加
		DrawListener mouse = new DrawListener();
//		jf.addMouseListener(mouse);
		drawPanel.addMouseListener(mouse);
//		jf.addMouseMotionListener(mouse);
		drawPanel.addMouseMotionListener(mouse);
		//形状按钮
		String[] name = { "曲线","直线", "椭圆", "矩形" ,"三角形","三点分形"};
		for (int i = 0; i < name.length; i++) {
			JButton button = new JButton(name[i]);
			button.setBackground(Color.cyan);
			button.setBounds(30, 30, 100, 30);
			jp.add(button);
			//按钮添加监听器(监听鼠标按下,画曲线时鼠标的移动)
			button.addActionListener(mouse);
			
		}
		
		//颜色按钮
		Color[] color = {Color.red,Color.green,Color.blue};
		for(int col = 0;col<color.length;col++) {
			JButton jcolor = new JButton();
			jcolor.setBackground(color[col]);
			jcolor.setBounds(30, 30, 100, 30);
			jp.add(jcolor);
			jcolor.addActionListener(mouse);//添加动作监听器
		}

		// 设置可见(画笔必须在其后面)
		jf.setVisible(true);

		// 添加画笔
		Graphics g = drawPanel.getGraphics();
		// 将画笔传递过去(将上一行的Graphics类属性g赋值给监听器对象的属性
		mouse.gr = g;
	
		//把shapeArr数组从DrawListener类传递给RepaintDrawUI
//		jf.shapeArr = mouse.shapeArr;
		drawPanel.shapeArr = mouse.shapeArr;
	}

	public static void main(String[] args) {
		DrawUI ui = new DrawUI();
		ui.showUI();
	}
}
package com.DrawBoardo921;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Random;

import javax.swing.JButton;

public class DrawListener implements MouseListener, ActionListener, MouseMotionListener {

	// 保存传递过来的属性
	public Graphics gr;
	public int x1, y1, x2, y2, x3, y3, x, y;
	public String name;
	int c = 0;

	
	Color color;// 记录颜色
	//定义Shapes数组,保存图形对象
	public Shapes[] shapeArr = new Shapes[1000];
	//定义操作数组的下标
	public int index=0;

	@Override
	public void mouseClicked(MouseEvent e) {

		System.out.println("鼠标点击了");
		if ("三角形".equals(name)) {
			if (c == 0) {
				x1 = e.getX();
				y1 = e.getY();
				c++;
				System.out.println("第1点" + x1 + "  " + y1);
			} else if (c == 1) {
				x2 = e.getX();
				y2 = e.getY();
				gr.drawLine(x1, y1, x2, y2);
				c++;
				System.out.println("第2点" + x1 + "  " + y1 + x2 + "  " + y2);
			} else if (c == 2) {
				x3 = e.getX();
				y3 = e.getY();
				gr.drawLine(x3, y3, x2, y2);
				gr.drawLine(x3, y3, x1, y1);
				System.out.println("第3点" + x3 + "  " + y3 + x2 + "  " + y2);
			}
			System.out.println("点击" + x1 + " " + y1 + "       " + x2 + " " + y2);
		}
		System.out.println("三角形");
	}

	@Override
	public void mousePressed(MouseEvent e) {
		x1 = e.getX();
		y1 = e.getY();
		System.out.println("按下");
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		x2 = e.getX();
		y2 = e.getY();
		System.out.println("释放");

		if(name != null) {
		//创建Shapes对象,保存数据。shapes的数据类型是Shapes,保存它的也的是Shapes类型,所以创建Shapes类型数组
		Shapes shape = new Shapes(x1,y1,x2,y2,x3,y3,name,color);
		//将shape的数据保存到数组中
		shapeArr[index++] = shape;
		shape.drawShapes(gr);
		
		if ("直线".equals(name)) {
			gr.drawLine(x1, y1, x2, y2);
		} else if ("椭圆".equals(name)) {
			if (x2 > x1) {
				gr.drawOval(x1, y1, Math.abs(x2 - x1), Math.abs(y2 - y1));
			} else {
				gr.drawOval(x2, y2, Math.abs(x1 - x2), Math.abs(y1 - y2));
			}
		} else if ("矩形".equals(name)) {
			gr.drawRect(Math.min(x1, x2), y1, Math.abs(x2 - x1), Math.abs(y2 - y1));
		} else if ("三点分形".equals(name)) {
			Random random = new Random();
			int x1 = (int) (Math.random() * 500);
			int y1 = (int) (Math.random() * 500);
			int x2 = (int) (Math.random() * 500);
			int y2 = (int) (Math.random() * 500);
			int x3 = (int) (Math.random() * 500);
			int y3 = (int) (Math.random() * 500);
			int xp = (int) (Math.random() * 500);
			int yp = (int) (Math.random() * 500);
			for (int i = 0; i < 1000; i++) {
				int k = random.nextInt(3);
				if (k == 0) {
					gr.drawLine((x1 + xp) / 2, (y1 + yp) / 2, (x1 + xp) / 2, (y1 + yp) / 2);
					xp = (x1 + xp) / 2;
					yp = (y1 + yp) / 2;
				} else if (k == 1) {
					gr.drawLine((x2 + xp) / 2, (y2 + yp) / 2, (x2 + xp) / 2, (y2 + yp) / 2);
					xp = (x2 + xp) / 2;
					yp = (y2 + yp) / 2;
				} else if (k == 2) {
					gr.drawLine((x3 + xp) / 2, (y3 + yp) / 2, (x3 + xp) / 2, (y3 + yp) / 2);
					xp = (x3 + xp) / 2;
					yp = (y3 + yp) / 2;
				}
			}
		}
	}
	}
	@Override
	public void mouseEntered(MouseEvent e) {

	}

	@Override
	public void mouseExited(MouseEvent e) {

	}

	@Override
	public void mouseDragged(MouseEvent e) {
		if ("曲线".equals(name)) {
			x = e.getX();
			y = e.getY();
			gr.drawLine(x2, y2, x, y);
			x2 = x;
			y2 = y;
			System.out.println("画曲线");
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void actionPerformed(ActionEvent e) {
		JButton jbu = (JButton) e.getSource(); // 看不懂
		Color color = jbu.getBackground();
		if (e.getActionCommand().equals("")) {
			gr.setColor(color);
		} else {
			name = e.getActionCommand();
		}
		System.out.println("String = " + name);
	}

	

	
}
package com.DrawBoardo921;

import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class RepaintDrawUI extends JFrame{
		//保存图形的数组(接收传过来的数组)
		public Shapes[] shapeArr;

}
package com.DrawBoardo921;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class Shapes {
	int x1,y1,x2,y2,x3,y3;
	Color color;
	Graphics gr;
	public String name;
	int c = 0;
	//构造方法初始化属性
	public Shapes(int x1,int y1,int x2,int y2,int x3,int y3,String name,Color color) {
	System.out.println("shapes");
		this.x1=x1;
		this.y1=y1;
		this.x2=x2;
		this.y2=y2;
		this.x3=x3;
		this.y3=y3;
		this.name=name;
		this.color=color;
	}
	//根据保存的数据还原图形
	public void drawShapes(Graphics g) {
		System.out.println("drawShapes:" + name);
		switch (name) {
		case"三角形" :
			if (c == 0) {
				c++;
				System.out.println("第1点" + x1 + "  " + y1);
			} else if (c == 1) {
				gr.drawLine(x1, y1, x2, y2);
				c++;
				System.out.println("第2点" + x1 + "  " + y1 + x2 + "  " + y2);
			} else if (c == 2) {
				gr.drawLine(x3, y3, x2, y2);
				gr.drawLine(x3, y3, x1, y1);
				System.out.println("第3点" + x3 + "  " + y3 + x2 + "  " + y2);
			}
			System.out.println("点击" + x1 + " " + y1 + "       " + x2 + " " + y2);
		System.out.println("三角形");
		break;
		case "直线":
			System.out.println("Graphics :"+gr);
			g.drawLine(x1, y1, x2, y2);
			break;
		case "椭圆":
			if (x2 > x1) {
				g.drawOval(x1, y1, Math.abs(x2 - x1), Math.abs(y2 - y1));
			} else {
				g.drawOval(x2, y2, Math.abs(x1 - x2), Math.abs(y1 - y2));
			}
			break;
		case "矩形":
			g.drawRect(Math.min(x1, x2), Math.min(y1, y2),Math.abs(x2 - x1), Math.abs(y2 - y1));
			break;
		case "三点分形":
			Random random = new Random();
			int x1 = (int) (Math.random() * 500);
			int y1 = (int) (Math.random() * 500);
			int x2 = (int) (Math.random() * 500);
			int y2 = (int) (Math.random() * 500);
			int x3 = (int) (Math.random() * 500);
			int y3 = (int) (Math.random() * 500);
			int xp = (int) (Math.random() * 500);
			int yp = (int) (Math.random() * 500);
			for (int i = 0; i < 1000; i++) {
				int k = random.nextInt(3);
				if (k == 0) {
					g.drawLine((x1 + xp) / 2, (y1 + yp) / 2, (x1 + xp) / 2, (y1 + yp) / 2);
					xp = (x1 + xp) / 2;
					yp = (y1 + yp) / 2;
				} else if (k == 1) {
					g.drawLine((x2 + xp) / 2, (y2 + yp) / 2, (x2 + xp) / 2, (y2 + yp) / 2);
					xp = (x2 + xp) / 2;
					yp = (y2 + yp) / 2;
				} else if (k == 2) {
					g.drawLine((x3 + xp) / 2, (y3 + yp) / 2, (x3 + xp) / 2, (y3 + yp) / 2);
					xp = (x3 + xp) / 2;
					yp = (y3 + yp) / 2;
				}
			}break;
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值