【问题标题】:How do I save a Winforms panel's drawing content to a file?如何将 Winforms 面板的绘图内容保存到文件?
【发布时间】:2014-11-14 17:35:10
【问题描述】:

我做了一个绘图程序,绘图内容(来自System.Drawing)被绘制在面板上。我现在尝试使用这种方法进行简单的保存,但我只得到一个空白图像。

我的位图的属性 .RawData 为 0。不知道这是否重要。

当我隐藏屏幕并再次显示时,面板变为空白。

附带说明,当我调用面板的 pnlPaint.Refresh() 时,面板变为空白。图丢了。这是一个双缓冲的东西,就像它没有保留值一样?

   private bool Save()
    {
        Bitmap bmpDrawing; 
        Rectangle rectBounds;

        try
        { 
            // Create bitmap for paint storage
            bmpDrawing = new Bitmap(pnlPaint.Width, pnlPaint.Height);

            // Set the bounds of the bitmap
            rectBounds = new Rectangle(0, 0, bmpDrawing.Width, bmpDrawing.Height);

            // Move drawing to bitmap
            pnlPaint.DrawToBitmap(bmpDrawing, rectBounds);

            // Save the bitmap to file
            bmpDrawing.Save("a.bmp", ImageFormat.Bmp);
        }
        catch (Exception e)
        {
            MessageBox.Show("Error on saving. Message: " + e.Message);
        }

        return true;
    }

【问题讨论】:

  • 实施问题属于 Stack Overflow。
  • 问题出在您未发布的代码中。您绘制面板的方式是错误的。使用它的 Paint 事件,不要使用 CreateGraphics()。
  • 即便如此,我还是用鼠标左键向下绘图,这需要在移动时抓取设备上下文。所以我认为最好通过在鼠标按下事件中传递它来完成。我目前还没有成功使用面板的绘画事件。
  • No.MouseDown 开始绘图后,MouseMove 可以收集点但绘图必须Paint 事件中发生或被触发,否则DrawToBitmap 调用将一事无成。
  • 好的。我已经收集了积分。鼠标移动后如何调用绘制事件? pnlPaint.Refresh()/Invalidate() 将线条保持一秒钟,直到面板再次变为空白。

标签: c# winforms


【解决方案1】:

这是一个最小的涂鸦程序,可让您绘制持久线:

List<Point> curPoints = new List<Point>();
List<List<Point>> allPoints = new List<List<Point>>();

private void pnlPaint_MouseDown(object sender, MouseEventArgs e)
{
    if (curPoints.Count > 1)
    {
        // begin fresh line or curve
        curPoints.Clear();
        // startpoint
        curPoints.Add(e.Location);
    }
}

private void pnlPaint_MouseUp(object sender, MouseEventArgs e)
{
    if (curPoints.Count > 1)
    {
        // ToList creates a copy
        allPoints.Add(curPoints.ToList());
        curPoints.Clear();
    }
}

private void pnlPaint_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button != MouseButtons.Left) return;
    // here we should check if the distance is more than a minimum!
    curPoints.Add(e.Location);
    // let it show
    pnlPaint.Invalidate();
}

private void pnlPaint_Paint(object sender, PaintEventArgs e)
{
    // here you can use DrawLines or DrawCurve
    // current line
    if (curPoints.Count > 1) e.Graphics.DrawCurve(Pens.Red, curPoints.ToArray());
    // other lines or curves
    foreach (List<Point> points in allPoints)
        if (points.Count > 1) e.Graphics.DrawCurve(Pens.Red, points.ToArray());
}

private void btn_undo_Click(object sender, EventArgs e)
{
    if (allPoints.Count > 1)
    {
        allPoints.RemoveAt(allPoints.Count - 1);
        pnlPaint.Invalidate();
    }
}

private void btn_save_Click(object sender, EventArgs e)
{
    string fileName = @"d:\test.bmp";
    Bitmap bmp = new Bitmap(pnlPaint.ClientSize.Width, pnlPaint.ClientSize.Width);
    pnlPaint.DrawToBitmap(bmp, pnlPaint.ClientRectangle);
    bmp.Save(fileName, ImageFormat.Bmp);
}

添加您的保存代码,如果您有问题,请直说..

更新:我添加了两个代码片段,它们执行保存和(无限)撤消..

注意 1:确保使用 DoubleBiffered 控件:PictureBox 或 Label 或带有 DoubleBuffered 的面板。

注意 2:这不支持单击创建点。由于没有DrawPoint,因此如果需要,则必须解决:

  • MouseUp当前曲线中只有一个点时,或者在 1 像素外添加一个额外的点;
  • 或允许单个点并添加FilleCircle 以在Paint 事件中显示它们。

【讨论】:

  • 对于实现,请前往screentogif.codeplex.com/SourceControl/latest GifRecorder/Controls/FreeDrawPanel.cs
  • 大约有。 2.45 万亿个现成的解决方案。通过研究最小解决方案来学习是更好的方法,imo。
  • a minimal solution >> 这是该代码的主键。 ;)
  • 我觉得这是解决问题的最佳方法,虽然它仅限于画线。绘制图像、圆圈等会导致更严重的问题。但仅基于我的问题,这很合适。我想寻找更简单的控件,尽管这对于所有绘画问题都更容易。我想我正在尝试做的类似于 MS Paint,在上面投掷图像、绘制线条、像素、形状,然后以 999 美元的价格出售。对于上面提到的问题,我喜欢这个。谢谢。
  • 这就是它的本质,但您可以将其用作基础。学习并扩展它!要继续进行更强大的绘图操作,您需要创建一个类 DrawingAction 并将 List&lt;Point&gt; 替换为 List&lt;DrawingAction&gt;.. DrawingAction 的属性将包括:类型、颜色、笔和画笔、文本等。只需一步一步来..! (去过那里..)
【解决方案2】:

在 GitHub 上查看此代码 ScreenToGif

文件夹GifRecorder\Controls\FreeDrawPanel.cs中有一个实现,它支持方形和圆形画笔、橡皮擦和保存输出图像。

【讨论】:

    【解决方案3】:

    我会跳过使用它不是为图形设计的面板,就像 ImageBox 那样 - 继续前进,然后您可以轻松保存内容。

    更新 图片框。我有一段时间没有使用 WinForms 了:D

    【讨论】:

    • 没有像 Winforms 中的 Imagebox 这样薄。
    • PictureBox 是一个强大的东西,具有缩放和三层显示等功能,但目前的问题是基本绘图,在那里非常相似,而不是稍微简单的保存..
    • 问题是关于“保存”绘图和空白面板是 OP 所述的旁注。
    • 好吧,从表面上看,是的。但问题的原因是错误的绘图方式。保存代码是/是正确的..
    猜你喜欢
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 2014-03-13
    • 1970-01-01
    相关资源
    最近更新 更多