【问题标题】:Capture a Form to a Bitmap after the Form has been resized调整窗体大小后将窗体捕获到位图
【发布时间】:2013-08-13 14:47:59
【问题描述】:

在 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 的位图,在后者的情况下包括非客户区,如下所示:

http://i.imgur.com/ZizXjNX.png

但是,如果我再次尝试捕获Form,我就会遇到问题。如果我在再次捕获之前调整了Form 的大小,则第二次捕获将显示非客户区不正确。

下面是一张图片来说明这一点 - 左边是表单在屏幕上的样子(正确),右边是上面的代码如何捕获它(不正确)。

http://i.imgur.com/y46kFDj.png

我没有从我自己的搜索中找到任何东西,所以想知道是否有人能指出我做错/没有做的事情?

【问题讨论】:

  • 也许没有代码可以解决这个问题,所以你只需要绕过它。在捕获表单图像之前,使用计时器或类似的新线程来计算一小段时间。
  • 这种情况会发生在调整大小期间,还是调整大小完成后的任何时候?
  • @DonBoitnott 对不起,我应该更清楚地说明这一点 - 它会在调整大小后随时发生。例如,我可以调整表单大小(调整大小已完成),等待 10 秒,然后捕获它,但它仍然显示不正确。令我困惑的是,客户区中的所有内容都是正确的,只有非客户区不正确。
  • 在我看来,Control bounds 的大小没有根据表单进行调整。它是停靠或锚定以确保调整大小,还是以某种方式在代码中处理?因为如果你的 hDC 是 Control 的,而且它更大,你会像第二个例子一样获得捕获。
  • 据我所知,边界是正确的——位图是根据控制边界创建的,并且始终是正确创建的。此外,客户区总是被正确捕获,非客户区似乎总是失败。

标签: c# .net screenshot bitblt nonclient-area


【解决方案1】:

我无法按要求解决这个问题(通过保留现有的捕获方法),而且由于这是针对原型应用程序,我目前没有时间进一步深入研究它。如果这个原型被选中或者我有另一个机会再次研究这个问题,我会相应地更新这个答案。

与此同时,我使用了以下方法作为替代方法。尽管使用不同的机制来捕获内容,但这会产生所需的输出。我不是很喜欢这个,因为它涉及到“弄乱”窗户和表格​​比我想要的要多,但现在就足够了。

基本上,我现在只需将有问题的窗口/表单放在前面,将其设置为最顶部,然后仅在窗口的边界上执行屏幕截图。正如我所说,比我想要的更混乱,但在实践中效果很好!

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-05
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    • 2019-01-09
    • 1970-01-01
    相关资源
    最近更新 更多