问题描述
我在从我的 winform 应用程序中创建位图图像时遇到问题.
I have a problem on creating bitmap image out of my winform application.
情况:
我有一个名为CanvasControl
"的 UserControl
,它接受 OnPaint
方法作为我的 Draw Pad 应用程序的画布.在此用户控件中,我有一个函数PrintCanvas()
",它将创建 UserControl
的屏幕截图图像到 PNG 文件中.下面是 PrintCanvas()
函数:
I have a UserControl
named as "CanvasControl
" that accepts OnPaint
method acting as canvas for my Draw Pad application. Inside this user control I have a function "PrintCanvas()
" that will create a screenshot image of the UserControl
into PNG file. Below is the PrintCanvas()
function:
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 +
@"ExperimentFilesExperiment1" + filename, ImageFormat.Png);
bmp.Dispose();
}
这个用户控件(CanvasControl
)在我的主窗体中被调用,用户将在其中绘制一些东西,然后可以选择使用保存按钮进行保存.保存按钮会调出UserControl
的PrintCanvas()
"函数.
This user control (CanvasControl
) is called out inside my main form where user will draw something and have an option to save afterwards using a save button. The save button will call out the "PrintCanvas()
" function of the UserControl
.
我得到了预期的输出图像文件,但问题是它是一个空白图像.
I get the output image file as expected, but the problem is it was a blank image.
到目前为止我所尝试的:
What I have tried so far:
为了测试这不是语法问题,我尝试将 PrintCanvas()
函数转移到我的主窗体中,令人惊讶的是,我在文件中获得了整个主窗体的图像,但 UserControl
在那里不可见.
To test that it is not a syntax issue, I tried to transfer the PrintCanvas()
function into my main form and surprisingly I get an image of the whole main form on file but the UserControl
is not visible there.
我是否错过了任何其他设置以使 winform UserControl
可打印?
Is there any other setup i missed out to make a winform UserControl
printable?
更新:(绘图程序)
- 充当画布的用户控件 - 此处代码
推荐答案
问题中的代码给出了第一个提示,但链接中的代码显示了问题的根源:您使用了 Graphics
绘图对象:
The code in the question gave a first hint but the code in the link showed the source of the problem: You use a 'wrong' instance of the Graphics
object for drawing:
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 的参数 图形.
This is one of the most common mistakes with winforms graphics! Never use CreateGraphics ! You always should draw onto the control surface with the Graphics object in a Paint or DrawXXX event. These events have a parameter e.Graphics
which is the only one that can draw persistent graphics.
持久意味着它总是会在必要时刷新,而不仅仅是在你触发它的时候.这是一个令人讨厌的错误,因为在您遇到外部事件需要重绘之前,一切似乎都正常工作:
Persistent means that it will always be refreshed when necessary, not just when you trigger it. This is a nasty error because everything seems to work until you come upon a situation when an outside event makes redrawing necessary:
- 最小化然后最大化表单
- 将其移出屏幕并再次移回
- 调用
DrawToBitmap
- ...
请注意,只有当您使用 PaintEventArgs e
参数中的 有效和当前 Graphics
对象时,所有功能才会真正起作用.
Note that all will only really work if you use the valid and current Graphics
object from the PaintEventArgs e
parameter.
所以,解决方法很简单:
So, the solution is simple:
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
有什么用?只对引诱新手犯这种错误有好处??
But what is the CreateGraphics
good for? It is only good for luring newbies into that error??
不完全;以下是它的一些用途:
Not quite; here are some uses for it:
- 绘制非永久性图形,例如橡皮筋矩形或特殊鼠标光标
- 在没有实际绘制的情况下使用
TextRenderer
或MeasureString
方法测量文本大小 - 使用
Graphics.DpiX/Y
查询屏幕或
Bitmap
分辨率- Drawing non-persistent graphics like a rubber-band rectangle or a special mouse cursor
- Measuring text sizes without actually drawing it with a
TextRenderer
or theMeasureString
method - Querying the screen or
Bitmap
resolution withGraphics.DpiX/Y
可能还有其他一些我现在想不起来的……
and probably some others I can't think of at the moment..
所以对于控件上的正常绘图总是使用 e.Grapahics
对象!您可以将其传递给子程序以使代码更有条理,但不要尝试缓存它;它必须是最新的!
So for normal drawing onto controls always use the e.Grapahics
object! You can pass it on to subroutines to make the code more structured, but do not try to cache it; it needs to be current!
这篇关于DrawToBitmap 返回空白图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!