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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:18:06