11

我希望在屏幕外将控件渲染到某个位图,以便我可以快速访问它。

不幸的是Control.DrawToBitmap,似乎绘制了调用它的整个控件,包括它的所有子控件。在内部,它向位图发出带有自备 DC 的 WM_PRINT 消息。然后将该临时位图传送到用户提供的位图。对我来说不可接受,我宁愿根据需要更新此位图,以便在需要位图时最小化我的性能损失。

在理想情况下,我希望表单表现得好像它在屏幕上可见(但它不能)。这意味着,如果某个控件的Text属性发生了变化,那么表单将部分失效。然后,捕获相关消息/事件将允许我为要绘制的表单指定我自己的 DC,或者将表单 DC 简单地 BitBlt 到我自己的。

我看过的一些方向:

  • PaintEventArgs参数 inOnPaint似乎包含一个成员 savedGraphicsState,也许它可以用来找出不需要失效的东西
  • 使表单可见但在屏幕区域之外。但是,控件不会被绘制。
  • 在窗口上手动调用 RedrawWindow(),同样的故事
4

3 回答 3

1

我认为有两个问题:

  1. 找出控件的无效区域(没有 Windows 的帮助)
  2. 仅渲染无效部分。

对于第一个问题,我认为您主要靠自己。您应该跟踪哪些控件发生了变化,并有需要更新的簿记。

对于第二个问题,您可以尝试自己发送 WM_PRINT 消息,并提供仅引用小位图的 DC。原始 DC API 允许您偏移和裁剪 HDC 的有效绘图区域。如果你很幸运,windows 会从 HDC 中推断出渲染区域,如果没有,大多数完全脱离位图的渲染命令应该很便宜,因为没有需要更改的像素。

您应该能够通过打印到 1x1 位图并测试它是否更快来验证这一点,和/或验证在 WM_PAINT 中发送的剪辑区域是否减小到位图大小。

于 2012-01-21T19:59:31.983 回答
0

我认为它会起作用,如果控件被克隆,那么您将获得一个不位于表单上且没有子控件的控件:

Control ctrl = ControlFactory.CloneCtrl(this.button3);
Bitmap bmp = new Bitmap(ctrl.Width, ctrl.Height);
ctrl.DrawToBitmap(bmp, new Rectangle(0, 0, ctrl.Width, ctrl.Height));
bmp.Save(@"C:\Users\Oli\Desktop\test.bmp");

我使用了The Code Project中由 lxwde 编写的ControlFactory

ControlFactory 并不完美,但它足够简单并且可以轻松改进。

于 2011-12-17T22:33:42.263 回答
0

我为您制作了一个示例项目,其中展示了一些 onPaint 事件。如果您看不到它以这种方式解决,只需更新示例。

问候! OnPaint 示例

在这里下载: http ://www.goldengel.ch/temp/OnPaintExample.zip

Private Sub Button1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles Button1.Paint
    Dim bm As New Bitmap(Me.Button1.Width, Me.Button1.Height, PixelFormat.Format32bppRgb)

    Button1.DrawToBitmap(bm, New Rectangle(0, 15, bm.Width -5, bm.Height+2))
    Using gr As Graphics = Graphics.FromImage(bm)
        gr.DrawString(DateTime.Now.ToLongTimeString, Me.Font, Brushes.Lime, 0, 0)
    End Using
    Me.PictureBox1.BackgroundImageLayout = ImageLayout.Tile
    Me.PictureBox1.BackgroundImage = bm

End Sub
    Public Class myTextBox
        Inherits System.Windows.Forms.TextBox


        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            MyBase.OnPaint(e)
            e.Graphics.Clear(Color.Yellow)
            e.Graphics.DrawString(DateTime.Now.ToLongTimeString, Me.Font, Brushes.Gray, 0, 0)
        End Sub

        Public Sub New()
            SetStyle(ControlStyles.UserPaint, True)
        End Sub
    End Class
于 2011-12-21T13:11:46.430 回答