You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#窗体中鼠标拖拽绘制正方形预览功能异常求助

问题描述

拖拽绘制正方形时,单独绘制功能正常,但预览图形无法被擦除。预期逻辑是:拖拽过程中用橡皮擦除上一次的预览图形,再绘制新的预览,直到鼠标松开完成最终正方形绘制。

绘制预览异常截图

相关代码

public partial class Form1 : Form
{
    Pen pen, eraser;
    Graphics graphics;
    Bitmap bitmap;
    Point startPoint, endPoint;
    int choice;
    Boolean draw;
    int width;
    int height;
    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (draw && choice == 1)
        {
            width = e.Location.X - startPoint.X;
            height = e.Location.Y - startPoint.Y;
            width = height;
            Rectangle shape = new Rectangle(startPoint.X, startPoint.Y, width, height);
            graphics.DrawRectangle(pen, shape);
            pictureBox1.Refresh();
            draw = false;
        }
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (draw && choice == 1)
        {
            width = e.Location.X - startPoint.X;
            height = e.Location.Y - startPoint.Y;
            width = height;
            graphics.DrawRectangle(eraser, startPoint.X, startPoint.Y, width, height);
            graphics.DrawRectangle(pen, startPoint.X, startPoint.Y, width, height);
            pictureBox1.Refresh();
        }
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        startPoint = e.Location;
        draw = true;
    }
}

问题原因及修复方案

核心问题是你试图直接在保存最终绘制内容的Bitmap上擦除预览,且没有记录上一次预览的矩形状态,导致旧预览无法被彻底清除。正确的做法是把最终绘制内容和临时预览分离:最终图形存在Bitmap中,预览仅在PictureBox的Paint事件里临时绘制,刷新时自动覆盖旧预览。

修改后的代码示例:

public partial class Form1 : Form
{
    Pen pen;
    Bitmap bitmap;
    Point startPoint;
    int choice;
    bool isDrawing;
    Point currentMousePoint;

    public Form1()
    {
        InitializeComponent();
        // 初始化画笔和画布Bitmap
        pen = new Pen(Color.Black, 2);
        bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        pictureBox1.Image = bitmap;
        // 绑定Paint事件用于绘制预览
        pictureBox1.Paint += PictureBox1_Paint;
    }

    private void PictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (isDrawing && choice == 1)
        {
            // 计算正方形边长,兼容不同拖拽方向
            int size = Math.Abs(currentMousePoint.X - startPoint.X);
            size = Math.Min(size, Math.Abs(currentMousePoint.Y - startPoint.Y));
            int x = startPoint.X < currentMousePoint.X ? startPoint.X : startPoint.X - size;
            int y = startPoint.Y < currentMousePoint.Y ? startPoint.Y : startPoint.Y - size;
            
            Rectangle previewRect = new Rectangle(x, y, size, size);
            // 用虚线绘制预览,和最终图形区分开
            using (Pen previewPen = new Pen(Color.Gray, 2))
            {
                previewPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                e.Graphics.DrawRectangle(previewPen, previewRect);
            }
        }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (isDrawing && choice == 1)
        {
            int size = Math.Abs(e.Location.X - startPoint.X);
            size = Math.Min(size, Math.Abs(e.Location.Y - startPoint.Y));
            int x = startPoint.X < e.Location.X ? startPoint.X : startPoint.X - size;
            int y = startPoint.Y < e.Location.Y ? startPoint.Y : startPoint.Y - size;
            
            Rectangle finalRect = new Rectangle(x, y, size, size);
            // 在Bitmap上绘制最终正方形
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.DrawRectangle(pen, finalRect);
            }
            pictureBox1.Refresh();
            isDrawing = false;
        }
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (isDrawing && choice == 1)
        {
            currentMousePoint = e.Location;
            pictureBox1.Refresh(); // 触发Paint事件重绘最新预览
        }
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        startPoint = e.Location;
        currentMousePoint = startPoint;
        isDrawing = true;
    }

    // 释放资源,避免内存泄漏
    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        base.OnFormClosing(e);
        pen.Dispose();
        bitmap.Dispose();
    }
}

关键改进点

  • 分离最终绘制和临时预览,彻底解决预览无法擦除的问题。
  • 兼容鼠标从任意方向拖拽的场景,不会出现反向绘制的异常。
  • 用虚线预览区分临时图形和最终图形,提升用户体验。
  • 正确释放GDI资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Andrew Sempros

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:26:17