如何在没有边框的Windows窗体上获得Aero Glass效果?

6

我正在尝试使用DWM API在VB.NET 2010应用程序中实现Aero Glass效果,但是如同函数调用所示,它扩展了框架的外观到客户区域,如果窗体没有边框,那么什么也不会发生,窗体将变得不可见。那么,我可以在没有任何边框的窗体中得到Aero Glass效果吗?

1个回答

13
如你所说,DwmExtendFrameIntoClientArea字面上将窗口边框的透明玻璃效果扩展到其客户区域,这意味着如果您的窗体FormBorderStyle设置为"None",则您的窗口将有效地变为不可见。 相反,您需要使用DwmEnableBlurBehindWindow API,该API可以在无需窗口框架/边框的情况下在窗口上启用玻璃模糊效果。它接受两个参数。第一个参数(hWnd)是您希望应用模糊效果的窗体的句柄。第二个参数(pBlurBehind)是通过引用传递的结构,其中包含效果的数据或参数。
因此,您还需要定义DWM_BLURBEHIND结构,它本身包含四个成员。第一个(dwFlags)是位组合的常量值,指示已设置此结构的哪些成员。第二个(fEnable)指示您是否要启用或禁用模糊效果。第三个(hRgnBlur)允许您指定客户区域内要应用模糊效果的特定区域;将其设置为Nothing表示整个客户区域都将具有模糊效果。第四个(fTransitionOnMaximized)允许您指定窗体的着色是否应过渡以匹配最大化的窗口。

以下是您必须在代码中包含的最终API声明,以便使用此函数:

<StructLayout(LayoutKind.Sequential)> _
Private Structure DWM_BLURBEHIND
    Public dwFlags As Integer
    Public fEnable As Boolean
    Public hRgnBlur As IntPtr
    Public fTransitionOnMaximized As Boolean
End Structure

Private Const DWM_BB_ENABLE As Integer = &H1
Private Const DWM_BB_BLURREGION As Integer = &H2
Private Const DWM_BB_TRANSITIONONMAXIMIZED As Integer = &H4

<DllImport("dwmapi.dll", PreserveSig:=False)> _
Private Shared Sub DwmEnableBlurBehindWindow(ByVal hWnd As IntPtr, ByRef pBlurBehind As DWM_BLURBEHIND)
End Sub

这里有一个简单的示例,说明如何在特定表单上调用此函数:

Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
    MyBase.OnLoad(e)

    ''#Set the form's border style to None
    Me.FormBorderStyle = FormBorderStyle.None

    ''#Whatever region that you fill with black will become the glassy region
    ''# (in this example, the entire form becomes transparent)
    Me.BackColor = Color.Black

    ''#Create and populate the blur-behind structure
    Dim bb As DWM_BLURBEHIND
    bb.dwFlags = DWM_BB_ENABLE
    bb.fEnable = True
    bb.hRgnBlur = Nothing

    ''#Enable the blur-behind effect
    DwmEnableBlurBehindWindow(Me.Handle, bb)
End Sub

如果您只想将模糊背景效果应用于表单的特定子区域,则需要为hRgnBlur成员提供有效的区域,并在dwFlags成员中添加DWM_BB_BLURREGION标志。您可以使用Region.GetHrgn方法获取要指定为hRgnBlur成员的区域句柄。例如,您可以使用以下代码:
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
    MyBase.OnLoad(e)

    ''#Set the form's border style to None
    Me.FormBorderStyle = FormBorderStyle.None

    ''#Fill the entire form with black to make it appear transparent
    Me.BackColor = Color.Black

    ''#Create a region corresponding to the area of the form you want to render as glass
    Using g As Graphics = Me.CreateGraphics
        Dim glassRect As New Rectangle(0, 0, 100, 150)
        Using rgn As New Region(glassRect)
            ''#Create and populate the blur-behind structure
            Dim bb As DWM_BLURBEHIND
            bb.dwFlags = DWM_BB_ENABLE Or DWM_BB_BLURREGION
            bb.fEnable = True
            bb.hRgnBlur = rgn.GetHrgn(g)

            ''#Enable blur-behind effect
            DwmEnableBlurBehindWindow(Me.Handle, bb)
        End Using
    End Using
End Sub

请注意,即使指定了要应用模糊背景效果的特定子区域,我仍将整个表单的背景颜色设置为黑色。这将导致我们指定的区域以玻璃般的模糊背景效果呈现,而表单的其余部分则呈透明状态。当然,您可以将表单的其余部分的背景颜色设置为任何颜色(尽管确保填充要呈现为玻璃的矩形的颜色为黑色,如前所述),但它将显示为部分透明,只是没有玻璃般的模糊背景效果。MSDN解释了这种情况的原因:
引用: 当您将模糊背景效果应用于窗口的子区域时,窗口的alpha通道用于非模糊区域。这可能会导致窗口中未模糊区域出现意外的透明度。因此,在应用子区域的模糊效果时要小心。
就我而言,这使得仅将此效果应用于表单窗口的子区域相对无价值。唯一似乎有意义的时候是,如果您想呈现任意非矩形形状为玻璃状,而表单的其余部分保持透明状态。

@Hans:我添加了一个区域的示例,尽管我指出,这似乎在WinForms中的实用性非常有限。 - Cody Gray
感谢您抽出时间并提供如此简明扼要的解释,按照您的建议操作后成功了。除了MSDN之外,我在哪里可以找到有关此API的其他方法的详细信息? - Kushal
@Kush:除了MSDN之外,我真的不太确定。你可以尝试使用pinvoke.net,但我发现他们的覆盖范围有点零散,最好交叉检查他们的内容与您在MSDN上找到的内容,因为有些声明是不正确或不完整的。对于我们.NET开发人员来说,微软未能使完全利用DWM功能变得非常方便。一旦您知道要导入的函数,Google搜索通常会出现一些博客文章(其中很多来自微软员工),但恐怕我不知道任何中心资源。 - Cody Gray
这个方案很好,但是如果使用win forms元素并应用这种玻璃效果呢?我认为看起来不太好,有什么解决办法吗? - Oscar Jara
@oscar:哈哈,是的,那个问题的被采纳答案链接到了我对另一个问题的回答。我忘记自己已经回答过关于这个主题的问题了... - Cody Gray
显示剩余3条评论

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