图形重绘

1.所有的swing组件都有一个paint方法,绘制组件本身;
2. 当改变窗体的状态(隐藏,改变大小)都会导致窗体上所有的组件重新调用paint方法(组件重绘),若没有编写重绘代码,会导致所绘画内容清空;
3. 想要完成图形重绘,需要两步:
一,保存图形的数据:根据图形对象设计对应的类;
二,继承绘制图形的面板,重写该面板类的paint方法。
(完成图形重绘涉及四个Java class)

在第一个Java class中------------------------------------------------------------

仅需要在原有基础上添加两步:
1.自定义面板MPanel:

MPanel drawPanel = new MPanel();

(MPanel继承JPanel,在 MPanel(第四个Java class) 中添加自定义的功能)
2.传递:

//把DrawListener类中的shapeArr数组传递给MPanel类
        drawPanel.shapeArr =  listener.shapeArr;

完整示例:

import javax.swing.*;
import java.awt.*;
import java.awt.Graphics;

/**
 * @author chen
 * @date 2025/7/13  19:22
 * @description

 *
 */
public class DrawUI {

    //显示画图工具的界面
    public void initUI(){
        JFrame jf = new JFrame();
        jf.setSize(900,900);
        jf.setTitle("画图工具");
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(3);
        JPanel northPanel = new JPanel();
        northPanel.setPreferredSize(new Dimension(0,40));
        northPanel.setBackground(Color.GREEN);
        jf.add(northPanel,BorderLayout.NORTH);

        DrawListener listener = new DrawListener();//在数组前创建对象listener

        String[] name = {"直线", "矩形","任意三角形", "多边形", "曲线","橡皮擦", "红色", "蓝色", "黑色","粗","细"};
        for (int i = 0; i < name.length; i++) {
            JButton jbu = new JButton(name[i]);
            northPanel.add(jbu);
            jbu.addActionListener(listener);
        }

        MPanel drawPanel = new MPanel();
        drawPanel.setBackground(Color.WHITE);
        jf.add(drawPanel,BorderLayout.CENTER);

        jf.setVisible(true);//

        //画笔:图形内容显示在哪个组件上,画笔就从该组件上获取
        //从窗体上获取画笔对象:一定要在窗体可见之后
        Graphics g = drawPanel.getGraphics();

        //给窗体添加鼠标监听器方法
        drawPanel.addMouseListener(listener);

        drawPanel.addMouseMotionListener(listener);
        //把画笔对象g 传递给DrawListener类
        listener.gr = g;
        drawPanel.shapeArr =  listener.shapeArr;
    }
    public static void main(String[] args){
        DrawUI ui = new DrawUI();
        ui.initUI();
    }
}

在第二个Java class中------------------------------------------------------------

1.定义所需要的属性:如颜色,粗细,数组等;

 //定义Shapes数组保存图形对象
    public Shapes[] shapeArr = new Shapes[2000];
    //操作数组的下标
    public int index = 0;
    public Color color = Color.BLACK;
    public float lineWidth = 1.0f;

(注意这里的颜色和粗细都需要单独用定义变量,以便于后续保存)
(2000,是数组保存对象数量,由于涉及曲线和橡皮擦这样需要大量保存的工具,故数字要设置的大一点)
2.颜色和粗细的控制如下:

public void actionPerformed(ActionEvent e) {
        //获取按钮上的内容
        String str = e.getActionCommand();;
        if("蓝色".equals(str)){
            color = Color.BLUE;
        }else if("红色".equals(str)){
            color = Color.RED;
        }else if("黑色".equals(str)) {
            color = Color.BLACK;
        }else if("粗".equals(str)){
            lineWidth = 5;
            Graphics2D g2 = (Graphics2D)gr;
            BasicStroke stroke = new BasicStroke(lineWidth);
            g2.setStroke(stroke);
        }else if("细".equals(str)){
            lineWidth = 1;
            Graphics2D g2 = (Graphics2D)gr;
            BasicStroke stroke = new BasicStroke(lineWidth);
            g2.setStroke(stroke);
        }else{
            name = e.getActionCommand();
        }
        gr.setColor(color);
        System.out.println("点击按钮!name = " + name);
    }

(注意粗细和原来没有用变量单独保存时的变化)
3.对于保存数据,可看作将需要的点的坐标的保存,再在第三个Java class中重绘,方法视所需决定,一般以以下格式:

Shapes shape = new Shapes(name,color,lineWidth,x1,y1,x2,y2,x3,y3);
shapeArr[index] = shape;
index++;

(可将颜色粗细一并保存并重绘)
(小括号里的保存内容和数量与第三个java class方法中的数据一一对应)

4.完整示例:

import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;

/**
 * @author chen
 * @date 2025/7/13  19:29
 * @description 实现接口:public class 子类 implements 接口,接口,,,{}
 * 实现接口一定要重写接口中所有的抽象方法
 */

public class DrawListener implements MouseListener, ActionListener, MouseMotionListener {
    //引用传递
    public Graphics gr;
    //全局变量:属性
    public int x1,y1,x2,y2,x3,y3,x4,y4;

    public String name;

    public Color color = Color.BLACK;
    public float lineWidth = 1.0f;

    //设置标记位,控制代码执行顺序
    public int flag = 1;
    public Shapes[] shapeArr = new Shapes[2000];
    //操作数组的下标
    public int index = 0;


    //动作监听器处理方法
    public void actionPerformed(ActionEvent e) {
        //获取按钮上的内容
        String str = e.getActionCommand();;
        if("蓝色".equals(str)){
            color = Color.BLUE;
        }else if("红色".equals(str)){
            color = Color.RED;
        }else if("黑色".equals(str)) {
            color = Color.BLACK;
        }else if("粗".equals(str)){
            lineWidth = 5;
            Graphics2D g2 = (Graphics2D)gr;
            BasicStroke stroke = new BasicStroke(lineWidth);
            g2.setStroke(stroke);
        }else if("细".equals(str)){
            lineWidth = 1;
            Graphics2D g2 = (Graphics2D)gr;
            BasicStroke stroke = new BasicStroke(lineWidth);
            g2.setStroke(stroke);
        }else{
            name = e.getActionCommand();
        }
        gr.setColor(color);
        System.out.println("点击按钮!name = " + name);
    }

    //鼠标监听器处理方法
    public void mouseClicked(MouseEvent e) {
        x3 = e.getX();
        y3 = e.getY();
        if("任意三角形".equals(name)){
            Shapes shape = new Shapes(name,color,lineWidth,x1,y1,x2,y2,x3,y3);
            shapeArr[index] = shape;
            index++;
            gr.drawLine(x1,y1,x3,y3);
            gr.drawLine(x2,y2,x3,y3);
            flag=1;
            System.out.println("x3 = "+x3+"   y3 = "+y3);
        }
        if("多边形".equals(name)){
            Shapes shape = new Shapes(name,color,lineWidth,x3,y3,x2,y2);
            shapeArr[index] = shape;
            index++;
            gr.drawLine(x2,y2,x3,y3);
            //让当前线段的终点变成下条线段的起点
            x2 = x3;
            y2 = y3;
            //判断是否双击: e.getClickCount() == 2
            if( e.getClickCount() == 2){
                gr.drawLine(x1,y1,x3,y3);
                flag = 1;
                shape = new Shapes(name,color,lineWidth,x1, y1, x3, y3);
                shapeArr[index] = shape;
                index++;
            }
        }
    }

    public void mousePressed(MouseEvent e) {
        System.out.println("按下");
        //获取当前坐标值
        //作用域:一对大括号就是一个独立作用域
        //局部变量:1.在方法(作用域)中定义的变量  2.方法的参数
        if(flag == 1) {
            x1 = e.getX();
            y1 = e.getY();
        }
        System.out.println("x1 = "+x1+"   y1 = "+y1);

    }

    public void mouseReleased(MouseEvent e) {
        System.out.println("松开");
        if(flag == 1) {
            x2 = e.getX();
            y2 = e.getY();
        }
        System.out.println("x2 = "+x2+"   y2 = "+y2);

        //绝对值
        int w = Math.abs(x2 - x1);
        int u = Math.abs(y2 - y1);
        int mx = Math.min(x1, x2);
        int my = Math.min(y1, y2);

        if ("直线".equals(name)) {
            //只需要在松开鼠标后保存数据
            //创建Shapes对象,把绘制直线的数据保存到对象中
            Shapes shape = new Shapes(name,color,lineWidth,x1,y1,x2,y2);
            shapeArr[index] = shape;
            index++;
        }
        if ("矩形".equals(name)) {
            //矩形
            Shapes shape = new Shapes(name,color,lineWidth,mx,my,w,u);
            shapeArr[index] = shape;
            index++;
            gr.drawRect(mx, my, w, u);
        }
        if("任意三角形".equals(name) ){
            gr.drawLine(x1, y1, x2, y2);
            flag++;
        }
        if("多边形".equals(name) && flag == 1){
            gr.drawLine(x1, y1, x2, y2);
            flag++;
            Shapes shape = new Shapes(name,color,lineWidth,x1,y1,x2,y2);
            shapeArr[index] = shape;
            index++;

        }
        if ("橡皮擦".equals(name)) {
            Graphics2D g2 = (Graphics2D) gr;
            BasicStroke stroke = new BasicStroke(1);
            g2.setStroke(stroke);
            gr.setColor(color);

        }
    }
    public void mouseDragged(MouseEvent e){

        if ("直线".equals(name)) {
            //绘制图形
            gr.setColor(Color.WHITE);
            gr.drawLine(x1, y1, x4, y4);
            x4 = e.getX();
            y4 = e.getY();
            gr.setColor(color);
            gr.drawLine(x1, y1, x4, y4);
        }
        if("曲线".equals(name)){

            x4 = e.getX();
            y4 = e.getY();
            Shapes shape = new Shapes(name,color,lineWidth,x1,y1,x4,y4);
            shapeArr[index] = shape;
            index++;
            gr.drawLine(x1,y1,x4,y4);
            x1=x4;
            y1=y4;
        }
        if("橡皮擦".equals(name)){
            x4 = e.getX();
            y4 = e.getY();
            Shapes shape = new Shapes(name,color,lineWidth,x1,y1,x4,y4);
            shapeArr[index] = shape;
            index++;
            Graphics2D g2 = (Graphics2D) gr;
            g2.setStroke(new BasicStroke(5));
            gr.setColor(Color.WHITE);
            gr.drawLine(x1, y1, x4, y4);
            x1 = x4;
            y1 = y4;
        }

    }
    public void mouseMoved(MouseEvent e){
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }
}

在第三个Java class中------------------------------------------------------------

1.调用方法:
public class Shapes{}
2.定义所需使用的属性:

public int x1,y1,x2,y2,x3,y3;
public String name="";
public Color color ;
public float lineWidth;

(注意这里使name为空字符串,是为了避免空指针异常NullPointerException报错)
3.在第二个java class中Shapes shape = new Shapes();
【每个类都有一个默认的无参构造方法,当自己定义构造方法,那么默认的无参构造方法就会被替代】
故想简化保存数据的步骤,可通过自定义构造方法的方式实现:

public Shapes(String name,Color color,float lineWidth,int x1,int y1,int x2,int y2,int x3,int y3){
        this.name = name;
        this.color = color;
        this.lineWidth = lineWidth;
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.x3 = x3;
        this.y3 = y3;
    }

(this 表示本类对象,super 表示当前类的父类对象)

方法重载(区别于方法重写)

方法重载:同一个方法通过参数选择实现不同的功能
使用条件:1.方法名重名 2.参数类型(个数,顺序)不一样

拓展

方法 格式:public 返回值类型 方法名(参数类型 参数名,){ 方法体…}
构造方法 格式:public 类名(参数类型 参数名,){ 方法体…}
构造方法和普通方法的区别:1.构造方法没有返回值类型 2.构造方法名必须是类名
构造方法的作用:1.创建对象 2.同时给多个属性初始化

4.使用方法,根据保存的数据还原图形:

public void drawShape(Graphics g){}

(drawShape是方法名,(Graphics g)是传入的参数,用g调用drawline等绘图API)
5.粗细颜色重新获得:

        g.setColor(color);
        Graphics2D g2 = (Graphics2D)g;
        BasicStroke stroke = new BasicStroke(lineWidth);
        g2.setStroke(stroke);

6.使用switch(name){}实现对不同图形的精准重绘:

switch (name){
           case "直线":
               g.drawLine(x1,y1,x2,y2);
               break;
           case "矩形":
               g.drawRect(x1,y1,x2,y2);
               break;
           case"任意三角形":
               g.drawLine(x1,y1,x2,y2);
               g.drawLine(x1,y1,x3,y3);
               g.drawLine(x2,y2,x3,y3);
               break;
           case"多边形":
               g.drawLine(x1,y1,x2,y2);
               break;
           case"曲线":
               g.drawLine(x1,y1,x2,y2);
               break;
           case"橡皮擦":
               g2.setStroke(new BasicStroke(5));
               g.setColor(Color.WHITE);
               g.drawLine(x1, y1, x2, y2);
               break;
       }

7.完整示例:

import java.awt.*;

/**
 * @author xuqiang
 * @date 2025/8/5  14:39
 * @description
 */
public class Shapes {
    public int x1,y1,x2,y2,x3,y3;

    public String name="";
    public Color color ;
    public float lineWidth;
    public Shapes(String name,Color color,float lineWidth,int x1,int y1,int x2,int y2,int x3,int y3){
        this.name = name;
        this.color = color;
        this.lineWidth = lineWidth;
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.x3 = x3;
        this.y3 = y3;
    }
    public Shapes(String name,Color color,float lineWidth,int x1,int y1,int x2,int y2){
        this.name = name;
        this.color = color;
        this.lineWidth = lineWidth;
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }



    public void drawShape(Graphics g){
        g.setColor(color);
        Graphics2D g2 = (Graphics2D)g;
        BasicStroke stroke = new BasicStroke(lineWidth);
        g2.setStroke(stroke);

        switch (name){
            case "直线":
                g.drawLine(x1,y1,x2,y2);
                break;
            case "矩形":
                g.drawRect(x1,y1,x2,y2);
                break;
            case"任意三角形":
                g.drawLine(x1,y1,x2,y2);
                g.drawLine(x1,y1,x3,y3);
                g.drawLine(x2,y2,x3,y3);
                break;
            case"多边形":
                g.drawLine(x1,y1,x2,y2);
                break;
            case"曲线":
                g.drawLine(x1,y1,x2,y2);
                break;
            case"橡皮擦":
                g2.setStroke(new BasicStroke(5));
                g.setColor(Color.WHITE);
                g.drawLine(x1, y1, x2, y2);
                break;
        }
    }
}

在第四个Java class中------------------------------------------------------------

1.自定义MPanel继承JPanel:

public class MPanel extends JPanel {}

2.定义属性(数组):

public Shapes[] shapeArr;

3.在paint方法中实现自定义的功能:

public void paint(Graphics g) {
        super.paint(g);

        for (int i = 0; i < shapeArr.length; i++) {
            Shapes shape = shapeArr[i];
            if (shape != null) {
                shape.drawShape(g);//防止空指针异常
            }
        }
    }

4.完整示例:

import javax.swing.*;
import java.awt.*;
/**
 * @author xuqiang
 * @date 2025/8/5  14:38
 * @description
 */
public class MPanel extends JPanel {
    public Shapes[] shapeArr;
    public void paint(Graphics g) {
        super.paint(g);

        for (int i = 0; i < shapeArr.length; i++) {
            Shapes shape = shapeArr[i];
            if (shape != null) {
                shape.drawShape(g);
            }
        }
    }
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐