关于画板和画板重绘
效果图如下(完整代码请看文末):
为什么要重绘
在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;
}
}
}