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
相关产品推荐
相关产品推荐

