调整窗体大小后,将窗体捕获到位图中

本文关键字:窗体 位图 调整 | 更新日期: 2023-09-27 18:27:35

在C#中工作,我有一个项目需要将ControlForm捕获到位图中。我有一个类,它在构造函数中使用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);
                }
            }
        }
    }

为我需要捕获的每个控件创建一个此类的实例,使用位图(在本例中,将其绘制到屏幕上),并在不再需要时处理对象。这非常有效,并为我提供了指定ControlForm的位图,在后者的情况下包括非客户端区域,如下所示:

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);
                    }
                }
            }
        }
    }
}