WinForms绘制填充图形求助:拖动时旧图形随Refresh消失
解决PictureBox拖动绘制时刷新丢失图形的问题
嘿,这个问题我之前也碰到过!核心原因是你调用Refresh()的时候,PictureBox会重新绘制它的背景,而之前画的图形并没有被持久化保存,所以就被清掉了。下面给你两种常用的解决方案,你可以根据自己的需求选:
方案一:用集合保存所有已绘制的图形(推荐)
这个方法的思路是把每一个已经绘制完成的图形都记录下来,每次PictureBox刷新时,重新绘制所有保存的图形,再加上拖动时的临时预览图形。
步骤1:定义图形数据类
首先咱们需要一个类来存储每个图形的关键信息,比如类型、坐标、颜色、是否填充等等:
public class DrawShape { public ShapeType Type { get; set; } // 自定义枚举,比如Rectangle、Circle等 public int X1 { get; set; } public int Y1 { get; set; } public int X2 { get; set; } public int Y2 { get; set; } public Color FillColor { get; set; } } public enum ShapeType { Rectangle, Circle, // 你的其他图形类型 }
步骤2:添加存储集合和临时变量
在你的窗体类里添加这些成员:
private List<DrawShape> _drawnShapes = new List<DrawShape>(); private DrawShape _tempShape = null; // 拖动时的临时图形 private bool _isDrawing = false; private int _startX, _startY;
步骤3:修改鼠标事件和Paint事件
更新你的鼠标事件逻辑,把完成的图形加入集合,拖动时更新临时图形,然后在Paint事件里绘制所有图形:
private void CizimPicture_MouseDown(object sender, MouseEventArgs e) { Cursor = Cursors.Cross; if (e.Button == MouseButtons.Left) { _isDrawing = true; _startX = e.X; _startY = e.Y; // 根据你当前选择的图形类型创建临时图形 _tempShape = new DrawShape { Type = 当前选择的图形类型, X1 = _startX, Y1 = _startY, FillColor = 当前选择的填充颜色 }; } } private void CizimPicture_MouseMove(object sender, MouseEventArgs e) { if (_isDrawing && _tempShape != null) { // 更新临时图形的结束坐标 _tempShape.X2 = e.X; _tempShape.Y2 = e.Y; CizimPicture.Refresh(); // 触发Paint事件重绘 } } private void CizimPicture_MouseUp(object sender, MouseEventArgs e) { if (_isDrawing && _tempShape != null) { // 把临时图形加入已绘制集合 _drawnShapes.Add(_tempShape); _tempShape = null; _isDrawing = false; Cursor = Cursors.Default; CizimPicture.Refresh(); } } private void CizimPicture_Paint(object sender, PaintEventArgs e) { // 先绘制所有已保存的图形 foreach (var shape in _drawnShapes) { DrawShapeToGraphics(e.Graphics, shape); } // 再绘制拖动时的临时图形 if (_tempShape != null) { DrawShapeToGraphics(e.Graphics, _tempShape); } } // 封装绘制单个图形的方法 private void DrawShapeToGraphics(Graphics g, DrawShape shape) { // 根据图形类型绘制填充图形 using (var brush = new SolidBrush(shape.FillColor)) { int width = Math.Abs(shape.X2 - shape.X1); int height = Math.Abs(shape.Y2 - shape.Y1); int x = Math.Min(shape.X1, shape.X2); int y = Math.Min(shape.Y1, shape.Y2); switch (shape.Type) { case ShapeType.Rectangle: g.FillRectangle(brush, x, y, width, height); break; case ShapeType.Circle: g.FillEllipse(brush, x, y, width, height); break; // 其他图形类型的绘制逻辑 } } }
方案二:使用Bitmap作为绘制画布
这个方法更简单,直接把绘制操作都在一个Bitmap上进行,然后把Bitmap赋值给PictureBox的Image属性,这样刷新时就不会丢失内容了。
步骤1:初始化Bitmap
在窗体加载时初始化Bitmap:
private Bitmap _drawBitmap; private void Form_Load(object sender, EventArgs e) { _drawBitmap = new Bitmap(CizimPicture.Width, CizimPicture.Height); CizimPicture.Image = _drawBitmap; }
步骤2:修改鼠标事件
拖动时先在临时Bitmap上预览,松开鼠标时把临时图形合并到主Bitmap:
private void CizimPicture_MouseDown(object sender, MouseEventArgs e) { Cursor = Cursors.Cross; if (e.Button == MouseButtons.Left) { _isDrawing = true; _startX = e.X; _startY = e.Y; } } private void CizimPicture_MouseMove(object sender, MouseEventArgs e) { if (_isDrawing) { // 创建临时Bitmap复制主Bitmap的内容 using (var tempBitmap = new Bitmap(_drawBitmap)) using (var g = Graphics.FromImage(tempBitmap)) using (var brush = new SolidBrush(当前填充颜色)) { int width = Math.Abs(e.X - _startX); int height = Math.Abs(e.Y - _startY); int x = Math.Min(_startX, e.X); int y = Math.Min(_startY, e.Y); // 在临时Bitmap上绘制预览图形 switch (当前选择的图形类型) { case ShapeType.Rectangle: g.FillRectangle(brush, x, y, width, height); break; case ShapeType.Circle: g.FillEllipse(brush, x, y, width, height); break; } // 把临时Bitmap赋值给PictureBox显示 CizimPicture.Image = tempBitmap; } } } private void CizimPicture_MouseUp(object sender, MouseEventArgs e) { if (_isDrawing) { _isDrawing = false; Cursor = Cursors.Default; // 把预览图形绘制到主Bitmap上 using (var g = Graphics.FromImage(_drawBitmap)) using (var brush = new SolidBrush(当前填充颜色)) { int width = Math.Abs(e.X - _startX); int height = Math.Abs(e.Y - _startY); int x = Math.Min(_startX, e.X); int y = Math.Min(_startY, e.Y); switch (当前选择的图形类型) { case ShapeType.Rectangle: g.FillRectangle(brush, x, y, width, height); break; case ShapeType.Circle: g.FillEllipse(brush, x, y, width, height); break; } } // 更新PictureBox显示主Bitmap CizimPicture.Image = _drawBitmap; } }
这两种方法都能解决你遇到的问题,方案一更灵活,适合后期扩展更多功能;方案二更直观,适合简单的画图场景。你可以根据自己的需求来选~
内容的提问来源于stack exchange,提问作者Kaepxer
相关产品推荐
相关产品推荐

