调整窗体大小后,将窗体捕获到位图中
本文关键字:窗体 位图 调整 | 更新日期: 2023-09-27 18:27:35
在C#中工作,我有一个项目需要将Control
或Form
捕获到位图中。我有一个类,它在构造函数中使用Control
参数,然后执行以下代码(在本例中简化)来保存Control
的位图。
public MyItem(Control control)
{
if (control != null)
{
Control rootParent = control;
while (rootParent.Parent != null)
rootParent = rootParent.Parent;
rootParent.BringToFront();
_bounds = control.Bounds;
Rectangle controlBounds;
if (control.Parent == null)
{
_bounds = new Rectangle(new Point(0, 0), control.Bounds.Size);
controlBounds = _bounds;
}
else
{
_bounds.Intersect(control.Parent.ClientRectangle);
_bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size);
controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size);
}
if (_bounds.Height > 0 && _bounds.Width > 0)
{
IntPtr hDC = IntPtr.Zero;
if (control.Parent == null && !Clarity.ClientAreaOnly)
// Used for capturing a form including non-client area
hDC = Win32.GetWindowDC(control.Handle);
else
// Used for capturing a form excluding non-client area or a control
hDC = control.CreateGraphics().GetHdc();
try
{
_controlBitmap = new Bitmap(_bounds.Width, _bounds.Height);
using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap))
{
IntPtr bitmapHandle = bitmapGraphics.GetHdc();
Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376);
bitmapGraphics.ReleaseHdc(bitmapHandle);
}
}
finally
{
if (hDC != IntPtr.Zero)
Win32.ReleaseDC(control.Handle, hDC);
}
}
}
}
为我需要捕获的每个控件创建一个此类的实例,使用位图(在本例中,将其绘制到屏幕上),并在不再需要时处理对象。这非常有效,并为我提供了指定Control
或Form
的位图,在后者的情况下包括非客户端区域,如下所示:
https://i.stack.imgur.com/nXi2C.png
但是,如果我再次尝试捕获Form
,就会遇到问题。如果我在再次捕获Form
之前已经调整了其大小,则第二次捕获将显示非客户端区域不正确。
下面的图片说明了这一点——左边是表单在屏幕上的样子(正确),右边是上面的代码如何捕捉它(不正确)。
https://i.stack.imgur.com/BKggN.png
我没有从自己的搜索中找到任何东西,所以想知道是否有人能指出我做错了什么/没有做错什么?
我无法按要求解决这个问题(通过保留现有的捕获方法),而且,由于这是一个原型应用程序,我现在没有时间进一步研究它。如果这个原型被发现,或者我有机会再次研究这个问题,我会相应地更新这个答案。
在此期间,我使用了以下方法作为替代方案。尽管使用不同的机制来捕获内容,但这会根据需要产生输出。我不太喜欢这个,因为它涉及到对窗户和形式的"破坏",这超出了我的意愿,但目前已经足够了。
基本上,我现在只需要将有问题的窗口/窗体放在最前面,将其设置为最上面,然后在窗口的边界上执行屏幕捕获。正如我所说,比我想要的更混乱,但在实践中效果足够好!
public MyItem(Control control)
{
if (control != null)
{
Control rootParent = control;
while (rootParent.Parent != null)
rootParent = rootParent.Parent;
rootParent.BringToFront();
_bounds = control.Bounds;
Rectangle controlBounds;
if (control.Parent == null)
{
_bounds = new Rectangle(new Point(0, 0), control.Bounds.Size);
controlBounds = _bounds;
}
else
{
_bounds.Intersect(control.Parent.ClientRectangle);
_bounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(_bounds.Location)), _bounds.Size);
controlBounds = new Rectangle(rootParent.PointToClient(control.Parent.PointToScreen(control.Location)), control.Size);
}
if (_bounds.Height > 0 && _bounds.Width > 0)
{
_controlBitmap = new Bitmap(_bounds.Width, _bounds.Height);
using (Graphics bitmapGraphics = Graphics.FromImage(_controlBitmap))
{
if (control.Parent == null)
{
Form form = control as Form;
Boolean currentTopMost = form.TopMost;
form.TopMost = true;
control.BringToFront();
bitmapGraphics.CopyFromScreen(control.Location, Point.Empty, _bounds.Size);
form.TopMost = currentTopMost;
}
else
{
IntPtr hDC = IntPtr.Zero;
try
{
hDC = control.CreateGraphics().GetHdc();
IntPtr bitmapHandle = bitmapGraphics.GetHdc();
Win32.BitBlt(bitmapHandle, 0, 0, _bounds.Width, _bounds.Height, hDC, _bounds.X - controlBounds.X, _bounds.Y - controlBounds.Y, 13369376);
bitmapGraphics.ReleaseHdc(bitmapHandle);
}
finally
{
if (hDC != IntPtr.Zero)
Win32.ReleaseDC(control.Handle, hDC);
}
}
}
}
}
}