Render Translucent/Transparent Overlay

馋奶兔 提交于 2019-12-04 03:25:52

The solution is not in your list. Solution #3 is to use UpdateLayeredWindow with a bitmap with an alpha channel. When updating the bitmap, you must paint only the areas that need updating, and use the fastest bitmap format (pre-multiplied ARBG). Here is an example of some graphics I created using solution #2, which seems fast enough: Translucent clock and calculator

Here are some more details. We have a class called GdiBuffer, containing a GDI handle field and a DC handle field (both encapsulated in classes, GdiHandle and DCHandle). It is initialized in the following way:

    public GdiBitmap(int width, int height)
    {
        using (Bitmap bitmap = new Bitmap(width, height))
            Initialize(bitmap);
    }
private void Initialize(Bitmap bitmap)
    {
        _size = bitmap.Size;
        _handle = new GdiHandle(bitmap.GetHbitmap(), true);
        _deviceContext = UnsafeNativeMethods.CreateCompatibleDC(IntPtr.Zero);
        UnsafeNativeMethods.SelectObject(_deviceContext, _handle);
    }

The Bitmap is a GDI+ bitmap. This means we _deviceContext is now representing both the GDI+ bitmap, and something we can use in GDI.

When it is time to update the screen, we pass a Form into the method in GdiBuffer that can update the screen:

            if (!form.Visible)
            return false;
        IntPtr formHandle = form.Handle;
        if (formHandle == IntPtr.Zero)
            return false;
        Check.Argument(opacity >= 0 && opacity <= 1, "opacity");
        // the future bounds was stored if the TranslucentForm Bounds property
        // changed at any time. the true update to the window bounds only
        // happens here, in the UpdateLayeredWindow call
        bool futureBoundsSet = form.FutureBoundsSet;
        Rect bounds = form.GetFutureBounds();
        SIZE newSize = new SIZE(bounds.Width, bounds.Height);
        POINT newPosition = new POINT(bounds.Left, bounds.Top);
        POINT pointSource = new POINT();
        BLENDFUNCTION blend = new BLENDFUNCTION((byte)(opacity * 255));
        IntPtr screenDC = UnsafeNativeMethods.GetDC(IntPtr.Zero);

        bool result;
        try
        {
            result = UnsafeNativeMethods.UpdateLayeredWindow(formHandle, screenDC, ref newPosition,
                ref newSize, _deviceContext, ref pointSource, 0, ref blend, UnsafeNativeMethods.ULW_ALPHA);
        }
        finally
        {
            if (screenDC != IntPtr.Zero)
                UnsafeNativeMethods.ReleaseDC(IntPtr.Zero, screenDC);
        }

To use our GdiBuffer internally:

_gdiBuffer = new GdiBitmap(_bufferSize);
_graphics = Graphics.FromHdc(_gdiBuffer.DeviceContext.DangerousGetHandle());

The _graphics field is where we actually draw.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!