【问题标题】:C# Transparent Form using UpdateLayeredWindow draw controls使用 UpdateLayeredWindow 绘制控件的 C# 透明表单
【发布时间】:2013-11-04 16:11:21
【问题描述】:

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

我一直在努力使用 TransparentColor+BackColor+Background Image 让它工作,但我总是以某些像素不透明而告终。所以我切换到 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)
        {
        }
    }

这里有一些图片可以更好地解释

【问题讨论】:

  • 您需要在覆盖的 OnPaint 中调用 base.OnPaint(e);
  • 你是在UpdateFormDisplay之后还是之前调用的?
  • 我都试过了,似乎都没有用
  • size 应该是非托管结构SIZE
  • @user2920222 尝试将UpdateFormDisplay 放在OnPaintBackground 中?顺便说一句,您不应该尝试过多地自定义winforms,如果您想要更好的解决方案,请尝试使用WPF

标签: c# winforms png transparent


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 2013-11-03
    • 2019-07-27
    相关资源
    最近更新 更多