使用UpdateLayeredWindow绘制控件的C#透明表单

时间:2013-10-25 13:45:25

标签: c# winforms png transparent

我正在开发一个需要透明背景的exe。我已经在Photoshop制作了图像并且它具有所有整洁的东西(阴影/不透明度,反射等)。

我一直在努力使用 TransparentColor + BackColor +背景图像让它工作,但我总是最终得到一些不透明的像素。所以我切换到 UpdateLayeredWindow ,它工作正常,但现在没有控制。

以下是我的一些代码

    private void Form1_Load(object sender, EventArgs e)
    {
        UpdateFormDisplay(this.BackgroundImage);
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        UpdateFormDisplay(this.BackgroundImage);

    }
    public void UpdateFormDisplay(Image backgroundImage)
    {
        IntPtr screenDc = API.GetDC(IntPtr.Zero);
        IntPtr memDc = API.CreateCompatibleDC(screenDc);
        IntPtr hBitmap = IntPtr.Zero;
        IntPtr oldBitmap = IntPtr.Zero;

        try
        {
            //Display-image
            Bitmap bmp = new Bitmap(backgroundImage);
            hBitmap = bmp.GetHbitmap(Color.FromArgb(0));  //Set the fact that background is transparent
            oldBitmap = API.SelectObject(memDc, hBitmap);

            //Display-rectangle
            Size size = bmp.Size;
            Point pointSource = new Point(0, 0);
            Point topPos = new Point(this.Left, this.Top);

            //Set up blending options
            API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
            blend.BlendOp = API.AC_SRC_OVER;
            blend.BlendFlags = 0;
            blend.SourceConstantAlpha = 255;
            blend.AlphaFormat = API.AC_SRC_ALPHA;

            API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, API.ULW_ALPHA);

            //Clean-up
            bmp.Dispose();
            API.ReleaseDC(IntPtr.Zero, screenDc);
            if (hBitmap != IntPtr.Zero)
            {
                API.SelectObject(memDc, oldBitmap);
                API.DeleteObject(hBitmap);
            }
            API.DeleteDC(memDc);
        }
        catch (Exception)
        {
        }
    }

以下是一些可以更好地解释的图片

enter image description here

enter image description here

1 个答案:

答案 0 :(得分:0)

如果要在使用UpdateLayeredWindow API的分层窗口中使用常规控件,则需要覆盖控件的OnPaint方法,将绘图重定向到屏幕后的位图,稍后您将使用该位图更新窗口外观的UpdateLayeredWindow方法。

如果您不想深入了解控件代码,或者没有多少自定义控件,可以使用WM_PRINT消息强制控件将自己绘制到提供的设备上下文中。经典窗口子类化(SetWindowLong / GetWindowLong)用于捕捉控件无效的时刻是有用的,但可能有点危险 - 你必须注意回调链。

最后,您可以使用轻量级(无窗口)控件。他们使用表单消息队列来接收事件并自己绘制,因此只需要表单绘制代码修改。一些标准winforms控件支持此模式。