VB.Net WinForms中Form的OnPaint()方法如何实现透明度刷新?

5
长话短说,我正在尝试编写一些类似于Growl的弹出式通知(应该出现在系统托盘旁边,并根据需要堆叠)。
我可以处理实例化/位置等,但我想添加非矩形toast的功能。我还希望具有Alpha透明度,因此在toast表单上使用半透明背景PNG将与其后面的桌面或窗口混合。
所以...先说显而易见的:
Form.TransparencyKey对我的需求不足,因为我想在某些地方获得50/50前景/背景,在其他地方获得0/100,在另一些地方获得100/0等等。
我的初始方法是覆盖OnBackgroundPaint()方法,注释掉对MyBase.OnBackgroundPaint的调用,并使用事件参数中的图形对象向表单绘制我想要的内容。
这似乎起初是有效的-目前,我只是为了测试而绘制一些矩形,因此PNG可能会出现新的困难,但我还没有到达那里。
我无法完成的是更新图形-第一次渲染表单时,它显示为我所期望的完美状态(没有边框,只有一些浮动在桌面上的矩形)。如果我将窗口移动到透明窗口后面,透明窗口不会更新/重新绘制。
我认为我需要调用Me.Invalidate()来强制重新绘制,但不确定何时应进行调用-我如何知道在我后面的窗口已更改其内容?
我错了吗?
非常感谢。
编辑:我尝试在计时器中放置一个Me.Invalidate(),只是为了测试重绘发生的方式-似乎它确实触发了重绘,但重绘发生在现有表单背景的上方-即,最初50%不透明的区域现在变成了75%不透明(50% +之前存在的50%)。
因此,在几次Invalidate()之后,我的表单显示为黑色框-我需要在重新绘制之前清除表单的背景,但Graphics.Clear(Color)似乎只是使用指定的颜色进行填充-显然,对于这个问题的目的,Colors.Transparent并不真正意味着透明-它似乎是在渲染窗口时使用的技巧“显示控件下面的内容”,但当我们处理表单本身时,它不起作用。
如果有人想要轻松复制,请参考下面的表单代码:
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 文章提供的解决方案实际上允许您在部分透明的窗体下单击透明区域以选择窗口。 - Alex Essilfie
1个回答

1

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

这里是链接到codeproject文章。我正在尝试上传VB项目,并将在完成后立即更新此答案。


编辑

这是我引用的CodeProject文章的VB.NET版本链接
http://www20.zippyshare.com/v/86701716/file.html

我会尝试审查您的代码,看看能否帮助您的情况。


关于这篇文章,您需要将任何32位PNG图像拖放到表单上,以显示带有该图像作为表单背景的表单。如果您想将表单的背景设置为该图像,则需要通过在代码中指定PNG文件来覆盖此过程。 - Alex Essilfie
谢谢 - 我应该能够稍微修改一下实现。如果您能够找出我的代码问题,我将不胜感激 - 我要去看看您转换后的代码。可能需要我几个小时才能回复您。 - Basic
我从来没有在任何应用程序中使用过这段代码,所以我不知道那个无事件副作用。今天下班后我会对此进行处理并回复你。请保持关注。 - Alex Essilfie
@Basiclife:看起来将控件绘制到位图上是唯一的解决方法。我在网站上查找了一下,这是我找到的PerPixel Alpha Blend (Add Controls) - Alex Essilfie
谢谢您回复我。虽然这不是我期望的完美解决方案,但我同意这可能是我能找到的最好的解决方案。 - Basic
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接