65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Forms控件:使用GDI+的VB.NET半透明控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.31/5 (11投票s)

2009年10月19日

CPOL

4分钟阅读

viewsIcon

122539

downloadIcon

10169

使用GDI+ & VB.NET构建标准的Windows Forms半透明控件

引言

本文的主要目的是展示如何通过继承扩展控件,在VB.NET中构建您自己的透明控件

此外,该类可以用作构建您自己的自定义透明控件(如PictureBoxButtonPanel等)的基类。

背景

由于Windows Form 控件是唯一通过其Opacity属性支持透明度的控件,我决定利用相同的策略来构建支持透明度的控件。

我看到了很多关于控件透明度的文章,并且研究了讨论相同问题的大多数技术,下面列出了一些这些技术

  • 调用控件父级的InvokePaintBackground并重写OnPaintBackground事件。
  • 绘制支持透明度的图像以避免由于双缓冲和闪烁引起的问题?
  • 重写CreateParams属性,设置ExStyle值以支持透明度,并在OnPaintBackground事件中,使用透明颜色填充控件的ClientRectangle

控件的行为

根据MSDN,控件类拥有三个方法,可以设置或检查控件的行为

  1. SetStyle方法:用于将ControlStyles位设置为指定的值,无论是True还是False
  2. GetStyle方法:用于检索ControlStyles
  3. UpdateStyles方法:用于强制将分配的ControlStyles位重新应用于控件,因为此方法将调用CreateParams方法以获取要应用于ExStyleStyleControlStyles
  4. ControlStyles枚举:与SetStyle方法一起使用,以指定控件的样式和行为

由于UpdateStyles方法允许我们在CreateParams方法中更改样式,因此我认为我们根本不应该重写CreateParams方法。 但有时,我们可能需要根据代码要求来执行此操作。

有关SetStyleControlStyles EnumGetStyleUpdateStyles的更多详细信息,您可以查看MSDN。

Using the Code

透明控件背后的概念分类如下

  • 使用SetStyleUpdateStyles方法更改CreateParams方法中的样式,这可以在控件构造函数中完成
        #Region " Constructor "
    
        Public Sub New()
    
            SetStyle(ControlStyles.SupportsTransparentBackColor, True)
            SetStyle(ControlStyles.Opaque, False)
            SetStyle(ControlStyles.DoubleBuffer, True)
            SetStyle(ControlStyles.AllPaintingInWmPaint, True)
            SetStyle(ControlStyles.UserPaint, True)
            UpdateStyles()
            ' ......... rest of the code 
            
        End Sub
    
    #End Region
  • BackColor属性:重写控件的BackColor属性,将其值设置为Color.Transparent并使用属性隐藏该属性。
        <System.ComponentModel.Browsable(False)> _
        <System.ComponentModel.EditorBrowsable_
        (System.ComponentModel.EditorBrowsableState.Never)> _
        <System.ComponentModel.DefaultValue(GetType(Color), "Transparent")> _
        <System.ComponentModel.Description("Set background color.")> _
        <System.ComponentModel.Category("Control Style")> _
        Public Overrides Property BackColor() As System.Drawing.Color
            Get
                Return m_backcolor
            End Get
            Set(ByVal value As System.Drawing.Color)
                m_backcolor = value
                Refresh()
            End Set
        End Property  
  • Opacity属性:此属性将用于设置控件的透明度百分比,我们应在此属性中使用UpdateStyles方法来设置控件的行为,如前所述。 此外,我正要编写一个类来将透明度值转换为string类型,但在.NET中,有一个内置的OpacityConverter类,这节省了一些时间。
        <System.ComponentModel.Browsable(True)> _
        <System.ComponentModel.EditorBrowsable_
        (System.ComponentModel.EditorBrowsableState.Always)> _
        <System.ComponentModel.DefaultValue(1.0R)> _
        <System.ComponentModel.TypeConverter(GetType(OpacityConverter))> _
        <System.ComponentModel.Description_
        ("Set the opacity percentage of the control.")> _
        <System.ComponentModel.Category("Control Style")> _
        Public Overridable Property Opacity() As Double
            Get
                Return m_opacity
            End Get
            Set(ByVal value As Double)
                If value = m_opacity Then
                    Return
                End If
                m_opacity = value
                UpdateStyles()
                Refresh()
            End Set
        End Property 
  • Transparent属性:指示控件是否应该是透明的。 当该值设置为false时,将跳过控件的透明度,并且控件的行为与正常控件相同。
        <System.ComponentModel.Browsable(True)> _
        <System.ComponentModel.EditorBrowsable_
        (System.ComponentModel.EditorBrowsableState.Always)> _
        <System.ComponentModel.DefaultValue(GetType(Boolean), "False")> _
        <System.ComponentModel.Description("Enable control trnasparency.")> _
        <System.ComponentModel.Category("Control Style")> _
        Public Overridable Property Transparent() As Boolean
            Get
                Return m_transparent
            End Get
            Set(ByVal value As Boolean)
                If value = m_transparent Then
                    Return
                End If
                m_transparent = value
                Refresh()
            End Set
        End Property
  • TransparentColor属性:此属性将用于设置填充颜色,该填充颜色将用于填充和绘制控件的ClientRectangle
       <System.ComponentModel.Browsable(True)> _
        <System.ComponentModel.EditorBrowsable_
        (System.ComponentModel.EditorBrowsableState.Always)> _
        <System.ComponentModel.DefaultValue(GetType(Color), "DodgerBlue")> _
        <System.ComponentModel.Description("Set the fill color of the control.")> _
        <System.ComponentModel.Category("Control Style")> _
        Public Overridable Property TransparentColor() As Color
            Get
                Return m_transparentColor
            End Get
            Set(ByVal value As Color)
                m_transparentColor = value
                Refresh()
            End Set
        End Property

绘制控件的透明度

透明度背后的诀窍是用SolidBrush绘制控件的ClientRectangle,其中它的值将使用BackColor属性设置

    Using sb As New SolidBrush(control.BackColor)
                g.FillRectangle(sb, control.ClientRectangle)
                sb.Dispose()

                ' .....rest of the code  

然后我们应该用另一个SolidBrush填充控件的clientRectangle,其中它的值将使用TransparentColor属性和Opacity属性设置

Using sbt As New SolidBrush(Color.FromArgb_
    (control.Opacity * 255, control.TransparentColor))
    g.FillRectangle(sbt, control.ClientRectangle)
    sbt.Dispose()
End Using
' ......rest of the code 

绘制控件的Background方法

    Public Overridable Sub DrawBackground_
    (ByVal g As Graphics, ByVal control As TransparentControl)

        If Transparent Then

            Using sb As New SolidBrush(control.BackColor)
                g.FillRectangle(sb, control.ClientRectangle)
                sb.Dispose()

                Using sbt As New SolidBrush(Color.FromArgb_
        (control.Opacity * 255, control.TransparentColor))
                    g.FillRectangle(sbt, control.ClientRectangle)
                    sbt.Dispose()
                End Using
            End Using

        Else

            Using sb As New SolidBrush(control.TransparentColor)
                g.FillRectangle(sb, control.ClientRectangle)
                sb.Dispose()
            End Using
        End If

    End Sub

我们可以根据我们的要求绘制任何我们想要的东西,并将代码传递给OnPaint事件,例如,让我们向控件添加边框,为此,还有两个额外的函数将用于使TransparentColor属性的值更暗或更亮,这两个函数也与opacity属性相关联

    Private Function GetLightColor(ByVal colorIn As Color, _
            ByVal percent As Single) As Color
        If percent < 0 OrElse percent > 100 Then
            Throw New ArgumentOutOfRangeException("percent must be between 0 and 100")
        End If
        Dim a As Int32 = colorIn.A * Me.Opacity
        Dim r As Int32 = colorIn.R + CInt(((255 - colorIn.R) / 100) * percent)
        Dim g As Int32 = colorIn.G + CInt(((255 - colorIn.G) / 100) * percent)
        Dim b As Int32 = colorIn.B + CInt(((255 - colorIn.B) / 100) * percent)
        Return Color.FromArgb(a, r, g, b)
    End Function

    Private Function GetDarkColor(ByVal colorIn As Color, _
            ByVal percent As Single) As Color
        If percent < 0 OrElse percent > 100 Then
            Throw New ArgumentOutOfRangeException("percent must be between 0 and 100")
        End If
        Dim a As Int32 = colorIn.A * Me.Opacity
        Dim r As Int32 = colorIn.R - CInt((colorIn.R / 100) * percent)
        Dim g As Int32 = colorIn.G - CInt((colorIn.G / 100) * percent)
        Dim b As Int32 = colorIn.B - CInt((colorIn.B / 100) * percent)
        Return Color.FromArgb(a, r, g, b)
    End Function

绘制控件的Border方法

    Public Overridable Sub DrawBorder(ByVal g As Graphics, _
            ByVal control As TransparentControl)
        Using p As New Pen(GetDarkColor(Me.TransparentColor, 40), 1)
            Dim rect As New Rectangle(ClientRectangle.X, ClientRectangle.Y, _
        ClientRectangle.Width - 1, ClientRectangle.Height - 1)
            rect.Inflate(-1, -1)
            g.DrawRectangle(p, rect)
            p.Dispose()
        End Using  

现在让我们将DrawBackgroundDrawBorder方法都传递给控件的OnPaint事件以完成工作

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        DrawBackground(e.Graphics, Me)
        DrawBorder(e.Graphics, Me)

    End Sub  

我相信我们可以使用相同的技术在控件内部绘制任何东西,并且同样应该支持透明度。 此外,我们可以使用相同的策略来构建一些其他半透明控件。

该控件还支持智能标记技术。 有关如何向控件添加智能标记的更多详细信息,您可以查看MSDN。

最后,只需构建控件并在您的表单中使用它即可。

注意

源代码是用Visual Studio 2008,.NET Framework 3.5编写的。

历史

  • 2009年10月10日:首次发布
  • 2009年10月13日:版本1.1
© . All rights reserved.