DrawToBitmap 返回空白图像

DrawToBitmap returning blank image

我在使用 winform 应用程序创建位图图像时遇到问题。

情况:

我有一个名为“CanvasControl”的 UserControl,它接受 OnPaint 方法作为我的 Draw Pad 应用程序的 canvas。在这个用户控件中,我有一个函数“PrintCanvas()”,它会将 UserControl 的屏幕截图图像创建到 PNG 文件中。下面是 PrintCanvas() 函数:

public void PrintCanvas(string filename = "sample.png")
{
    Graphics g = this.CreateGraphics();
    //new bitmap object to save the image        
    Bitmap bmp = new Bitmap(this.Width, this.Height);
    //Drawing control to the bitmap        
    this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
    bmp.Save(Application.StartupPath + 
        @"\ExperimentFiles\Experiment1" + filename, ImageFormat.Png);
    bmp.Dispose();
}

此用户控件 (CanvasControl) 在我的主窗体中调用,用户将在其中绘制一些内容,然后可以选择使用保存按钮进行保存。保存按钮会调出UserControl.

的“PrintCanvas()”函数

我得到了预期的输出图像文件,但问题是它是一张空白图像。

到目前为止我尝试过的:

为了测试这不是语法问题,我尝试将 PrintCanvas() 函数转移到我的主窗体中,令人惊讶的是我在文件中得到了整个主窗体的图像,但是 UserControl在那里不可见。

我是否错过了任何其他设置来使 winform UserControl 可打印?

更新:(绘图例程)

  1. 用户控件充当 canvas - code here

问题中的代码给出了第一个提示,但 link 中的代码显示了问题的根源:您使用 Graphics 对象的 'wrong' 实例进行绘图:

protected override void OnPaint(PaintEventArgs e)
{
  // If there is an image and it has a location,
  // paint it when the Form is repainted.
  Graphics graphics = this.CreateGraphics();
  ..

这是winforms图形最常见的错误之一! 切勿使用 CreateGraphics!您始终应该在 Paint 或 DrawXXX 事件中使用 Graphics 对象在控制面上绘图。 这些事件有一个参数 e.Graphics,它是唯一可以绘制 persistent 图形。

Persistent的意思是它会一直在需要的时候刷新,而不仅仅是你触发它的时候。这是一个严重的错误,因为在您遇到外部事件需要重新绘制的情况之前,一切似乎都正常:

  • 最小化然后最大化表单
  • 将其移出屏幕再移回
  • 呼叫DrawToBitmap
  • ...

请注意,只有当您使用 PaintEventArgs e 参数中的 有效和当前 Graphics 对象时,所有这些才会真正起作用。

所以,解决方法很简单:

protected override void OnPaint(PaintEventArgs e)
{
  // If there is an image and it has a location,
  // paint it when the Form is repainted.
  Graphics graphics = e.Graphics();  // << === !!
  ..

但是 CreateGraphics 有什么用?只是为了引诱新手犯那个错误??

不完全是;这里有一些用途:

  • 绘制非持久图形,如橡皮筋矩形或特殊鼠标光标
  • 使用 TextRendererMeasureString 方法测量文本大小而不实际绘制它
  • 查询屏幕或 Bitmap 分辨率 Graphics.DpiX/Y

可能还有一些我现在想不起来的..

所以要在控件上正常绘制 总是 使用 e.Grapahics 对象!您可以将它传递给子例程以使代码更加结构化,但不要尝试缓存它;它必须是最新的!