一、需求分析与架构设计

1.1 功能需求拆解

功能项

具体要求

图形绘制

支持直线、矩形、椭圆、三角形、曲线五种基本图形

颜色切换

提供红色、蓝色两种颜色选择

图形持久化

窗口重绘后图形不消失

用户交互

直观的按钮操作,鼠标绘制图形

1.2 技术架构设计

采用 MVC 架构模式:

模型层:Shapes类(存储图形数据)

视图层:MPanel(绘图面板)、DrawUI(界面布局)

控制层:DrawListener(事件处理)

二、模型层实现详解

2.1 Shapes 类设计

2.1.1 数据结构
public class Shapes {

    public String name;  // 图形类型

    public int x1, y1, x2, y2;  // 起点和终点坐标

    public int x3, y3;  // 三角形第三点坐标

    public Color color;  // 图形颜色

    // 自绘制方法

    public void drawShape(Graphics g) { ... }

}

2.1.2 坐标处理策略

图形类型

坐标处理逻辑

直线

直接连接 (x1,y1) 和 (x2,y2)

矩形

左上角坐标为 (min (x1,x2), min (y1,y2)),宽高为 abs (x2-x1) 和 abs (y2-y1)

椭圆

外接矩形与矩形相同,使用 drawOval 方法绘制

三角形

连接三个点形成封闭图形

曲线

由多个短直线段组成,每段连接前一点和当前点

三、视图层实现详解

3.1 MPanel 类(绘图面板)

3.1.1 核心功能
  1. 继承关系:
public class MPanel extends JPanel { ... }
    3.1.2 图形持久化实现
    1. 关键依赖:依赖控制器中的shapeArr数组
    2. 数据流向:控制器更新数组 → 面板重绘时读取数组

    四、控制层实现详解

    4.1 DrawListener 类

    4.1.1 事件处理接口
    public class DrawListener implements
    
        MouseListener, MouseMotionListener, ActionListener { ... }
    4.1.2 核心状态变量

    变量名

    类型

    作用

    shapeArr

    Shapes[]

    存储所有图形的数组

    index

    int

    当前图形索引

    currentShape

    String

    当前选择的图形类型

    currentColor

    Color

    当前选择的颜色

    flag

    int

    三角形绘制状态标志(1 - 绘制第一条边,2 - 等待第三点)

    五、核心技术问题解决方案

    5.1 窗口重绘时图形消失问题

    5.1.1 问题根源分析
    1. Swing 重绘机制:
      1. 窗口状态变化时,系统自动调用paint方法
      2. 默认paint方法只绘制当前时刻的静态内容
    2. 数据丢失原因:
      1. 未将图形数据存储在持久化结构中
      2. 每次重绘时从空白状态开始
    5.1.2 解决方案
    1. 数据存储方案:

    // DrawListener类中

    public Shapes[] shapeArr = new Shapes[1000];

    1. 保存图形逻辑

    private void saveShape(String type, int x1, int y1, int x2, int y2, int x3, int y3) {

        Shapes shape = new Shapes();

        shape.name = type;

        shape.x1 = x1;

        shape.y1 = y1;

        shape.x2 = x2;

        shape.y2 = y2;

        shape.x3 = x3;

        shape.y3 = y3;

        shape.color = currentColor;

        shapeArr[index++] = shape;

    }

    1. 重绘恢复逻辑:

    // MPanel类的paint方法

    @Override

    public void paint(Graphics g) {

        super.paint(g);

        for (Shapes shape : shapeArr) {

            if (shape != null) {

                shape.drawShape(g);

            }

        }

    }

    5.1.3 技术要点
    1. 数组作为存储容器:
      1. 优点:简单直接,无需额外依赖
      2. 缺点:固定大小,需处理溢出问题
    2. 数据流向控制:

    sequenceDiagram

        participant 用户

        participant DrawListener

        participant MPanel

       

        用户->>DrawListener: 绘制图形

        DrawListener->>DrawListener: 创建图形对象

        DrawListener->>DrawListener: 添加到shapeArr

        DrawListener->>MPanel: 调用repaint()

        MPanel->>DrawListener: 获取shapeArr

        MPanel->>Shapes: 调用drawShape()

    六、三角形分步绘制实现

    6.1 状态管理机制

    1. 状态变量:

    private int flag = 1;  // 三角形绘制状态标志

    1. 状态转换:

    stateDiagram

        [*] --> 选择三角形

        选择三角形 --> 绘制第一条边: flag=1

        绘制第一条边 --> 等待第三点: flag=2

        等待第三点 --> 完成绘制: 鼠标点击

        完成绘制 --> [*]: flag=1

    6.2 关键代码实现

    1. 第一步:绘制第一条边:

    @Override

    public void mouseReleased(MouseEvent e) {

        if ("三角形".equals(currentShape) && flag == 1) {

            saveShape("三角形", x1, y1, x2, y2, 0, 0);

            flag = 2;  // 切换到等待第三点状态

        }

    }

    1. 第二步:确定第三点:

    @Override

    public void mouseClicked(MouseEvent e) {

        if ("三角形".equals(currentShape) && flag == 2) {

            // 更新最后一个三角形的第三点坐标

            shapeArr[index - 1].x3 = e.getX();

            shapeArr[index - 1].y3 = e.getY();

            flag = 1;  // 重置标志

        }

    }

    七、曲线平滑绘制实现

    7.1 算法原理

    1. 曲线分解:
      1. 将曲线分解为多个短直线段
      2. 每段连接前一点和当前点
    2. 视觉效果:
      1. 短直线段足够密集时,视觉上形成平滑曲线

    7.2 关键代码

    @Override

    public void mouseDragged(MouseEvent e) {

        if ("曲线".equals(currentShape)) {

            x2 = e.getX();

            y2 = e.getY();

           

            // 保存当前线段

            saveShape("曲线", x1, y1, x2, y2, 0, 0);

           

            // 更新起点为当前终点,形成连续线段

            x1 = x2;

            y1 = y2;

           

            // 实时重绘

            drawPanel.repaint();

        }

    }

    八、程序运行流程

    8.1 初始化阶段

    1. 创建主窗口和组件
    2. 初始化事件监听器
    3. 设置布局和初始状态

    8.2 用户交互阶段

    1. 选择图形类型和颜色
    2. 在绘图区域进行鼠标操作
    3. 监听器捕获并处理事件

    8.3 图形绘制阶段

    1. 创建图形对象
    2. 添加到图形数组
    3. 触发面板重绘

    8.4 窗口重绘阶段

    1. 系统调用paint方法
    2. 从数组获取图形数据
    3. 重新绘制所有图形

    更多推荐