VB.Net WinForms表单OnPaint()透明度刷新

VB.Net WinForms表单OnPaint()透明度刷新,.net,vb.net,winforms,gdi+,.net,Vb.net,Winforms,Gdi+,长话短说,我正在尝试编写一些toast风格的弹出式通知(类似于咆哮),它们应该出现在系统托盘旁边,并根据需要堆叠 我可以处理实例化/位置等。。。但我想增加一个非矩形烤面包机的功能。我还希望有Alpha透明度,这样toast表单上的半透明背景PNG将与它后面的桌面或窗口混合 所以。。。要避开显而易见的问题,请执行以下操作: Form.TransparencyKey不足以满足我的需要,因为它是一种全有或全无的透明度效果,我希望在某些地方获得50/50的前景/背景,在其他地方为0/100,在其他地方为

长话短说,我正在尝试编写一些toast风格的弹出式通知(类似于咆哮),它们应该出现在系统托盘旁边,并根据需要堆叠

我可以处理实例化/位置等。。。但我想增加一个非矩形烤面包机的功能。我还希望有Alpha透明度,这样toast表单上的半透明背景PNG将与它后面的桌面或窗口混合

所以。。。要避开显而易见的问题,请执行以下操作:

Form.TransparencyKey不足以满足我的需要,因为它是一种全有或全无的透明度效果,我希望在某些地方获得50/50的前景/背景,在其他地方为0/100,在其他地方为100/0,等等

我最初的方法是重写OnBackgroundPaint()方法,注释掉对MyBase.OnBackgroundPaint的调用,并使用eventargs中的graphics对象精确地绘制我想要的表单

这似乎是可行的开始-目前,我只是为了测试目的画一些矩形,所以PNG可能会带来新的困难,但我还没有做到这一点

我没能完成的是更新图形——第一次呈现表单时,它会像我期望的那样完美地显示出来(没有边框,只是桌面上漂浮着一些矩形)。如果将窗口移到透明窗口后面,则透明窗口不会更新/重新绘制

我相信我需要打电话给我。Invalidate()以强制重新绘制,但我不确定何时应该打电话-我如何知道我身后的窗口已更改其“内容”

我是不是走错了路

非常感谢

编辑:我尝试在计时器中放置一个Me.Invalidate(),只是为了测试重画是如何发生的-看起来它确实触发了重画,但重画操作发生在现有的表单背景上-即原来50%不透明的区域现在是75%不透明的(50%+50%以前的情况)

因此,在几个Invalidate()之后,我的表单显示为一个黑匣子-我需要在重新绘制图形之前清除表单的背景。clear(Color)似乎只是用指定的颜色填充-显然出于这个问题的目的,颜色。透明并不真正意味着透明——它似乎是渲染窗口时使用的一种技巧,用于“显示此窗口下的控件内容”,但在处理窗体本身时,这一技巧不起作用

如果有人想轻松复制,我的表单代码如下:

Imports System.Drawing
Public Class TransparentForm

    Private Timer As Timers.Timer

    Private Sub TransparentForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Timer = New Timers.Timer
        AddHandler Timer.Elapsed, AddressOf Timer_Tick
        Timer.Interval = 100
        Timer.Start()
    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
        ''MyBase.OnPaintBackground(e)
        Console.WriteLine("BackgroundPainted")
        For x = 0 To 9
            e.Graphics.FillRectangle(
                New SolidBrush(Color.FromArgb(CInt(x / 10 * 255), 127, 127, 127)),
                CInt(x * Me.Width / 10),
                0,
                CInt(Me.Width / 10),
                Me.Height
            )
        Next
    End Sub

    Sub Timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
        Me.Invalidate()
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        Console.WriteLine("Painted")
    End Sub

    Protected Overrides Sub OnInvalidated(ByVal e As System.Windows.Forms.InvalidateEventArgs)
        MyBase.OnInvalidated(e)
        Console.WriteLine("Invalidated")
    End Sub

End Class

有一篇CodeProject文章展示了如何使用png作为表单的“皮肤”。显然,这支持部分透明,而不是
Form.TransparencyKey
提供的50/50方法

这是codeproject文章的第一部分。我正在尝试用VB上传这个项目,并将在完成后尽快更新这个答案


编辑

下面是我上面引用的CodeProject文章的VB.NET版本的链接。


我将尝试查看您的代码,看看可以做些什么来帮助您解决问题。

我查看了您的代码,并意识到它以某种程度的[部分]透明度绘制表单。但是,它不允许点击“透明”区域。CodeProject文章提供的解决方案实际上允许您单击透明区域以选择部分透明窗体下的窗口。您必须在窗体上删除任何32位PNG图像,才能以该图像作为窗体的背景显示窗体。如果你想将表单的背景设置为图像,你必须在代码中指定一个PNG文件来覆盖这个过程。谢谢-我应该可以稍微修改一下实现。如果您能找出我的代码的问题,我将不胜感激——我要去看看您转换的代码。我可能需要几个小时才能回复您OK,有趣的副作用-使用提供的技术确实会产生完全兼容alpha透明的表单,但是,根本不会呈现控件或其他UI元素。此外,表单上的控件未收到任何事件。你有什么建议吗?我从来没有在任何应用程序中实际使用过代码,所以我不知道没有事件的副作用。我今天下班后再做,然后再给你打电话。请继续关注。作为一种临时解决方法,在应用位图之前,我已将该方法修改为doa Control.DrawToBitmap(背景位图)。这至少允许我显式调用的控件被呈现-显然这仍然不能解决根本问题。。。