如何仅重绘分层窗口的区域?

时间:2013-03-19 00:33:30

标签: c# winforms layered-windows

我有一个分层窗口,通常以这种方式绘制:

    private void SelectBitmap(Bitmap bitmap)
    {
        IntPtr screenDc = GetDC(IntPtr.Zero);
        IntPtr memDc = CreateCompatibleDC(screenDc);
        IntPtr hBitmap = IntPtr.Zero;
        IntPtr hOldBitmap = IntPtr.Zero;

        try
        {
            hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
            hOldBitmap = SelectObject(memDc, hBitmap);

            POINT sourceLocation = new POINT(0, 0);
            BLENDFUNCTION blend = new BLENDFUNCTION();

            blend.BlendOp = AC_SRC_OVER;
            blend.BlendFlags = 0;
            blend.SourceConstantAlpha = 255;
            blend.AlphaFormat = AC_SRC_ALPHA;

            SIZE newSize = new SIZE(bitmap.Width, bitmap.Height);
            POINT newLocation = new POINT(Location.X, Location.Y);

            UpdateLayeredWindow(Handle, screenDc,
                ref newLocation, ref newSize,
                memDc,
                ref sourceLocation, 0,
                ref blend,
                ULW_ALPHA);
        }
        finally
        {
            ReleaseDC(IntPtr.Zero, screenDc);

            if (hBitmap != IntPtr.Zero)
            {
                SelectObject(memDc, hOldBitmap);
                DeleteObject(hBitmap);
            }

            DeleteDC(memDc);
        }
    }

然而,这显然会在每次调用时重绘整个窗口。大窗户的性能消耗很大。 (甚至在我的顶级PC上,这让我想知道人们如何在Win2K中处理它)

If I read the Microsoft paper on the layered window, it says:UpdateLayeredWindow始终更新整个窗口。要更新窗口的一部分,请使用传统的WM_PAINT并使用SetLayeredWindowAttributes设置混合值。

我只是无法理解上述内容。 WM_PAINT如何访问分层窗口位图并在窗口上仅重绘部分窗口位图?根据我的理解,分层窗口只是禁用WM_PAINT消息并期望用户自己绘制窗口。显然没有办法将WM_PAINT绑定到完成的自定义绘图。

我错过了一些非常明显的东西吗?

1 个答案:

答案 0 :(得分:1)

经过长时间的分析,我发现它并不是真正的分层窗口更新是瓶颈。刷新整个屏幕,上面的SelectBitmap方法,在1920 * 1200上花了大约6-8ms。当然,不是很惊人,但足以刷新30 FPS +。

在我的情况下,性能消耗来自某个线程要求每次重绘几乎一百次刷新,使一切都迟钝。解决方案是分解刷新/重绘并将它们分开。一个人会更新(联合)一个区域而另一个人在没有绘图的情况下会占用该区域,绘制它然后清空它。