Windows Forms控件:使用GDI+的VB.NET半透明控件
使用GDI+ & VB.NET构建标准的Windows Forms半透明控件
引言
本文的主要目的是展示如何通过继承扩展控件,在VB.NET中构建您自己的透明控件。
此外,该类可以用作构建您自己的自定义透明控件(如PictureBox
、Button
、Panel
等)的基类。
背景
由于Windows Form 控件是唯一通过其Opacity
属性支持透明度的控件,我决定利用相同的策略来构建支持透明度的控件。
我看到了很多关于控件透明度的文章,并且研究了讨论相同问题的大多数技术,下面列出了一些这些技术
- 调用控件父级的
InvokePaintBackground
并重写OnPaintBackground
事件。 - 绘制支持透明度的图像以避免由于双缓冲和闪烁引起的问题?
- 重写
CreateParams
属性,设置ExStyle
值以支持透明度,并在OnPaintBackground
事件中,使用透明颜色填充控件的ClientRectangle
。
控件的行为
根据MSDN,控件类拥有三个方法,可以设置或检查控件的行为
SetStyle
方法:用于将ControlStyles
位设置为指定的值,无论是True
还是False
GetStyle
方法:用于检索ControlStyles
位UpdateStyles
方法:用于强制将分配的ControlStyles
位重新应用于控件,因为此方法将调用CreateParams
方法以获取要应用于ExStyle
和Style
的ControlStyles
位ControlStyles
枚举:与SetStyle
方法一起使用,以指定控件的样式和行为
由于UpdateStyles
方法允许我们在CreateParams
方法中更改样式,因此我认为我们根本不应该重写CreateParams
方法。 但有时,我们可能需要根据代码要求来执行此操作。
有关SetStyle
、ControlStyles Enum
、GetStyle
和UpdateStyles
的更多详细信息,您可以查看MSDN。
Using the Code
透明控件背后的概念分类如下
- 使用
SetStyle
和UpdateStyles
方法更改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
现在让我们将DrawBackground
和DrawBorder
方法都传递给控件的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