IssueVision的PaneCaption控件源码分析
今天看了看IssueVision的源代码,把学习中的东西记录下来,以免忘掉了。
' Custom control that draws the caption for each pane. Contains an active
' state and draws the caption different for each state. Caption is drawn
' with a gradient fill and antialias font.
Imports System.Drawing.Drawing2D '使用GDI+绘制渐变背景和表面文字需要引用的类
Imports System.ComponentModel
Public Class PaneCaption
Inherits System.Windows.Forms.UserControl
' const values
'用来控制控件表面文字绘制的属性和控件默认的缺省属性
Private Class Consts
Public Const DefaultHeight As Integer = 26
Public Const DefaultFontName As String = "Tahoma"
Public Const DefaultFontSize As Integer = 12
Public Const PosOffset As Integer = 4 '文字相对于容器的绘制坐标位移
End Class
' internal members
Private m_active As Boolean = False '控件激活和无效两种状态控制
Private m_antiAlias As Boolean = True '用来控制控件表面文字的显示质量
Private m_allowActive As Boolean = True
Private m_text As String = ""
'两种状态默认文字、背景渐变颜色
Private m_colorActiveText As Color = Color.Black
Private m_colorInactiveText As Color = Color.White
Private m_colorActiveLow As Color = Color.FromArgb(255, 165, 78)
Private m_colorActiveHigh As Color = Color.FromArgb(255, 225, 155)
Private m_colorInactiveLow As Color = Color.FromArgb(3, 55, 145)
Private m_colorInactiveHigh As Color = Color.FromArgb(90, 135, 215)
' gdi objects
'绘制显示效果的笔刷
Private m_brushActiveText As SolidBrush
Private m_brushInactiveText As SolidBrush
Private m_brushActive As LinearGradientBrush
Private m_brushInactive As LinearGradientBrush
Private m_format As StringFormat
' public properties
' the caption of the control
'设置控件中的文本,并且在属性面板中可以选择
<Description("Text displayed in the caption."), _
Category("Appearance"), DefaultValue("")> _
Public Property Caption() As String
Get
Return m_text
End Get
Set(ByVal value As String)
m_text = value
Invalidate() '重会控件的显示
End Set
End Property
'两个同样的属性,但是在即使按照上边控制Caption属性的方式来控制Text属性,属性面板中也不显示Text属性,不知动为什么?
Public Overrides Property Text() As String
Get
Return Me.Caption
End Get
Set(ByVal Value As String)
Me.Caption = Value
End Set
End Property
' if the caption is active or not
<Description("The active state of the caption, draws the caption with different gradient colors."), _
Category("Appearance"), DefaultValue(False)> _
Public Property Active() As Boolean
Get
Return m_active
End Get
Set(ByVal value As Boolean)
m_active = value
Invalidate()
End Set
End Property
' if should maintain an active and inactive state
<Description("True always uses the inactive state colors, false maintains an active and inactive state."), _
Category("Appearance"), DefaultValue(True)> _
Public Property AllowActive() As Boolean
Get
Return m_allowActive
End Get
Set(ByVal value As Boolean)
m_allowActive = value
Invalidate()
End Set
End Property
' if the caption is active or not
<Description("If should draw the text as antialiased."), _
Category("Appearance"), DefaultValue(True)> _
Public Property AntiAlias() As Boolean
Get
Return m_antiAlias
End Get
Set(ByVal value As Boolean)
m_antiAlias = value
Invalidate()
End Set
End Property
#Region " color properties "
<Description("Color of the text when active."), _
Category("Appearance"), DefaultValue(GetType(Color), "Black")> _
Public Property ActiveTextColor() As Color
Get
Return m_colorActiveText
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.Black
m_colorActiveText = Value
m_brushActiveText = New SolidBrush(m_colorActiveText)
Invalidate()
End Set
End Property
<Description("Color of the text when inactive."), _
Category("Appearance"), DefaultValue(GetType(Color), "White")> _
Public Property InactiveTextColor() As Color
Get
Return m_colorInactiveText
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.White
m_colorInactiveText = Value
m_brushInactiveText = New SolidBrush(m_colorInactiveText)
Invalidate()
End Set
End Property
<Description("Low color of the active gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "255, 165, 78")> _
Public Property ActiveGradientLowColor() As Color
Get
Return m_colorActiveLow
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(255, 165, 78)
m_colorActiveLow = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
<Description("High color of the active gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "255, 225, 155")> _
Public Property ActiveGradientHighColor() As Color
Get
Return m_colorActiveHigh
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(255, 225, 155)
m_colorActiveHigh = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
<Description("Low color of the inactive gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "3, 55, 145")> _
Public Property InactiveGradientLowColor() As Color
Get
Return m_colorInactiveLow
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(3, 55, 145)
m_colorInactiveLow = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
<Description("High color of the inactive gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "90, 135, 215")> _
Public Property InactiveGradientHighColor() As Color
Get
Return m_colorInactiveHigh
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(90, 135, 215)
m_colorInactiveHigh = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
#End Region
' internal properties
' brush used to draw the caption
Private ReadOnly Property TextBrush() As SolidBrush
Get
Return CType(IIf(m_active AndAlso m_allowActive, _
m_brushActiveText, m_brushInactiveText), SolidBrush)
End Get
End Property
' gradient brush for the background
Private ReadOnly Property BackBrush() As LinearGradientBrush
Get
Return CType(IIf(m_active AndAlso m_allowActive, _
m_brushActive, m_brushInactive), LinearGradientBrush)
End Get
End Property
' ctor
Public Sub New()
MyBase.New()
' this call is required by the Windows Form Designer
InitializeComponent()
' set double buffer styles
'设置双重缓冲,以改善控件的显示效果
Me.SetStyle(ControlStyles.DoubleBuffer Or ControlStyles.UserPaint Or _
ControlStyles.AllPaintingInWmPaint Or ControlStyles.ResizeRedraw, True)
' init the height
Me.Height = Consts.DefaultHeight
' format used when drawing the text
m_format = New StringFormat
m_format.FormatFlags = StringFormatFlags.NoWrap
m_format.LineAlignment = StringAlignment.Center '保证控件中文字的垂直对齐效果
'在不完全适合布局形状的字符串中修整字符,指定将文本修整成最接近的字符,并在被修整的行的末尾插入一个省略号
m_format.Trimming = StringTrimming.EllipsisCharacter
' init the font
Me.Font = New Font(Consts.DefaultFontName, Consts.DefaultFontSize, FontStyle.Bold)
' create gdi objects
Me.ActiveTextColor = m_colorActiveText
Me.InactiveTextColor = m_colorInactiveText
' setting the height above actually does this, but leave
' in incase change the code (and forget to init the
' gradient brushes)
CreateGradientBrushes()
End Sub
' internal methods
' the caption needs to be drawn
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
DrawCaption(e.Graphics)
End Sub
' draw the caption
Private Sub DrawCaption(ByVal g As Graphics)
' background
g.FillRectangle(Me.BackBrush, Me.DisplayRectangle)
' caption
If m_antiAlias Then
'控制文本呈现模式,指定在无提示的情况下使用每个字符的 AntiAlias
'标志符号位图来绘制字符。由于采用了 AntiAlias,质量会得到改善。
'由于关闭了提示,主干宽度差可能会比较明显。
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
End If
' need a rectangle when want to use ellipsis
'绘制区域相对于控件有一定的位移
Dim bounds As RectangleF = New RectangleF(Consts.PosOffset, 0, _
Me.DisplayRectangle.Width - Consts.PosOffset, Me.DisplayRectangle.Height)
g.DrawString(m_text, Me.Font, Me.TextBrush, bounds, m_format)
End Sub
' clicking on the caption does not give focus,
' handle the mouse down event and set focus to self
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
MyBase.OnMouseDown(e)
If Me.m_allowActive Then Me.Focus()
End Sub
Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
MyBase.OnSizeChanged(e)
' create the gradient brushes based on the new size
CreateGradientBrushes()
End Sub
Private Sub CreateGradientBrushes()
' can only create brushes when have a width and height
If Me.Width > 0 AndAlso Me.Height > 0 Then
If Not (m_brushActive Is Nothing) Then m_brushActive.Dispose()
m_brushActive = New LinearGradientBrush(Me.DisplayRectangle, _
m_colorActiveHigh, m_colorActiveLow, LinearGradientMode.Vertical)
If Not (m_brushInactive Is Nothing) Then m_brushInactive.Dispose()
m_brushInactive = New LinearGradientBrush(Me.DisplayRectangle, _
m_colorInactiveHigh, m_colorInactiveLow, LinearGradientMode.Vertical)
End If
End Sub
#Region " Windows Form Designer generated code "
'UserControl overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
'
'PaneCaption
'
Me.Name = "PaneCaption"
Me.Size = New System.Drawing.Size(150, 30)
End Sub
#End Region
End Class
' state and draws the caption different for each state. Caption is drawn
' with a gradient fill and antialias font.
Imports System.Drawing.Drawing2D '使用GDI+绘制渐变背景和表面文字需要引用的类
Imports System.ComponentModel
Public Class PaneCaption
Inherits System.Windows.Forms.UserControl
' const values
'用来控制控件表面文字绘制的属性和控件默认的缺省属性
Private Class Consts
Public Const DefaultHeight As Integer = 26
Public Const DefaultFontName As String = "Tahoma"
Public Const DefaultFontSize As Integer = 12
Public Const PosOffset As Integer = 4 '文字相对于容器的绘制坐标位移
End Class
' internal members
Private m_active As Boolean = False '控件激活和无效两种状态控制
Private m_antiAlias As Boolean = True '用来控制控件表面文字的显示质量
Private m_allowActive As Boolean = True
Private m_text As String = ""
'两种状态默认文字、背景渐变颜色
Private m_colorActiveText As Color = Color.Black
Private m_colorInactiveText As Color = Color.White
Private m_colorActiveLow As Color = Color.FromArgb(255, 165, 78)
Private m_colorActiveHigh As Color = Color.FromArgb(255, 225, 155)
Private m_colorInactiveLow As Color = Color.FromArgb(3, 55, 145)
Private m_colorInactiveHigh As Color = Color.FromArgb(90, 135, 215)
' gdi objects
'绘制显示效果的笔刷
Private m_brushActiveText As SolidBrush
Private m_brushInactiveText As SolidBrush
Private m_brushActive As LinearGradientBrush
Private m_brushInactive As LinearGradientBrush
Private m_format As StringFormat
' public properties
' the caption of the control
'设置控件中的文本,并且在属性面板中可以选择
<Description("Text displayed in the caption."), _
Category("Appearance"), DefaultValue("")> _
Public Property Caption() As String
Get
Return m_text
End Get
Set(ByVal value As String)
m_text = value
Invalidate() '重会控件的显示
End Set
End Property
'两个同样的属性,但是在即使按照上边控制Caption属性的方式来控制Text属性,属性面板中也不显示Text属性,不知动为什么?
Public Overrides Property Text() As String
Get
Return Me.Caption
End Get
Set(ByVal Value As String)
Me.Caption = Value
End Set
End Property
' if the caption is active or not
<Description("The active state of the caption, draws the caption with different gradient colors."), _
Category("Appearance"), DefaultValue(False)> _
Public Property Active() As Boolean
Get
Return m_active
End Get
Set(ByVal value As Boolean)
m_active = value
Invalidate()
End Set
End Property
' if should maintain an active and inactive state
<Description("True always uses the inactive state colors, false maintains an active and inactive state."), _
Category("Appearance"), DefaultValue(True)> _
Public Property AllowActive() As Boolean
Get
Return m_allowActive
End Get
Set(ByVal value As Boolean)
m_allowActive = value
Invalidate()
End Set
End Property
' if the caption is active or not
<Description("If should draw the text as antialiased."), _
Category("Appearance"), DefaultValue(True)> _
Public Property AntiAlias() As Boolean
Get
Return m_antiAlias
End Get
Set(ByVal value As Boolean)
m_antiAlias = value
Invalidate()
End Set
End Property
#Region " color properties "
<Description("Color of the text when active."), _
Category("Appearance"), DefaultValue(GetType(Color), "Black")> _
Public Property ActiveTextColor() As Color
Get
Return m_colorActiveText
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.Black
m_colorActiveText = Value
m_brushActiveText = New SolidBrush(m_colorActiveText)
Invalidate()
End Set
End Property
<Description("Color of the text when inactive."), _
Category("Appearance"), DefaultValue(GetType(Color), "White")> _
Public Property InactiveTextColor() As Color
Get
Return m_colorInactiveText
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.White
m_colorInactiveText = Value
m_brushInactiveText = New SolidBrush(m_colorInactiveText)
Invalidate()
End Set
End Property
<Description("Low color of the active gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "255, 165, 78")> _
Public Property ActiveGradientLowColor() As Color
Get
Return m_colorActiveLow
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(255, 165, 78)
m_colorActiveLow = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
<Description("High color of the active gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "255, 225, 155")> _
Public Property ActiveGradientHighColor() As Color
Get
Return m_colorActiveHigh
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(255, 225, 155)
m_colorActiveHigh = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
<Description("Low color of the inactive gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "3, 55, 145")> _
Public Property InactiveGradientLowColor() As Color
Get
Return m_colorInactiveLow
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(3, 55, 145)
m_colorInactiveLow = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
<Description("High color of the inactive gradient."), _
Category("Appearance"), DefaultValue(GetType(Color), "90, 135, 215")> _
Public Property InactiveGradientHighColor() As Color
Get
Return m_colorInactiveHigh
End Get
Set(ByVal Value As Color)
If Value.Equals(Color.Empty) Then Value = Color.FromArgb(90, 135, 215)
m_colorInactiveHigh = Value
CreateGradientBrushes()
Invalidate()
End Set
End Property
#End Region
' internal properties
' brush used to draw the caption
Private ReadOnly Property TextBrush() As SolidBrush
Get
Return CType(IIf(m_active AndAlso m_allowActive, _
m_brushActiveText, m_brushInactiveText), SolidBrush)
End Get
End Property
' gradient brush for the background
Private ReadOnly Property BackBrush() As LinearGradientBrush
Get
Return CType(IIf(m_active AndAlso m_allowActive, _
m_brushActive, m_brushInactive), LinearGradientBrush)
End Get
End Property
' ctor
Public Sub New()
MyBase.New()
' this call is required by the Windows Form Designer
InitializeComponent()
' set double buffer styles
'设置双重缓冲,以改善控件的显示效果
Me.SetStyle(ControlStyles.DoubleBuffer Or ControlStyles.UserPaint Or _
ControlStyles.AllPaintingInWmPaint Or ControlStyles.ResizeRedraw, True)
' init the height
Me.Height = Consts.DefaultHeight
' format used when drawing the text
m_format = New StringFormat
m_format.FormatFlags = StringFormatFlags.NoWrap
m_format.LineAlignment = StringAlignment.Center '保证控件中文字的垂直对齐效果
'在不完全适合布局形状的字符串中修整字符,指定将文本修整成最接近的字符,并在被修整的行的末尾插入一个省略号
m_format.Trimming = StringTrimming.EllipsisCharacter
' init the font
Me.Font = New Font(Consts.DefaultFontName, Consts.DefaultFontSize, FontStyle.Bold)
' create gdi objects
Me.ActiveTextColor = m_colorActiveText
Me.InactiveTextColor = m_colorInactiveText
' setting the height above actually does this, but leave
' in incase change the code (and forget to init the
' gradient brushes)
CreateGradientBrushes()
End Sub
' internal methods
' the caption needs to be drawn
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
DrawCaption(e.Graphics)
End Sub
' draw the caption
Private Sub DrawCaption(ByVal g As Graphics)
' background
g.FillRectangle(Me.BackBrush, Me.DisplayRectangle)
' caption
If m_antiAlias Then
'控制文本呈现模式,指定在无提示的情况下使用每个字符的 AntiAlias
'标志符号位图来绘制字符。由于采用了 AntiAlias,质量会得到改善。
'由于关闭了提示,主干宽度差可能会比较明显。
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
End If
' need a rectangle when want to use ellipsis
'绘制区域相对于控件有一定的位移
Dim bounds As RectangleF = New RectangleF(Consts.PosOffset, 0, _
Me.DisplayRectangle.Width - Consts.PosOffset, Me.DisplayRectangle.Height)
g.DrawString(m_text, Me.Font, Me.TextBrush, bounds, m_format)
End Sub
' clicking on the caption does not give focus,
' handle the mouse down event and set focus to self
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
MyBase.OnMouseDown(e)
If Me.m_allowActive Then Me.Focus()
End Sub
Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
MyBase.OnSizeChanged(e)
' create the gradient brushes based on the new size
CreateGradientBrushes()
End Sub
Private Sub CreateGradientBrushes()
' can only create brushes when have a width and height
If Me.Width > 0 AndAlso Me.Height > 0 Then
If Not (m_brushActive Is Nothing) Then m_brushActive.Dispose()
m_brushActive = New LinearGradientBrush(Me.DisplayRectangle, _
m_colorActiveHigh, m_colorActiveLow, LinearGradientMode.Vertical)
If Not (m_brushInactive Is Nothing) Then m_brushInactive.Dispose()
m_brushInactive = New LinearGradientBrush(Me.DisplayRectangle, _
m_colorInactiveHigh, m_colorInactiveLow, LinearGradientMode.Vertical)
End If
End Sub
#Region " Windows Form Designer generated code "
'UserControl overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
'
'PaneCaption
'
Me.Name = "PaneCaption"
Me.Size = New System.Drawing.Size(150, 30)
End Sub
#End Region
End Class
这是个很简单的控件,但是我想对初学者应该是有帮助的,主要体现在以下几点:
背景的渐变绘制
表面文字质量的控制
设计过程中的控件绘制控制
文字与控件调整的关系
属性面板的控制
总结一下:
由于是第一次学习制作控件,看看这个源代码对自己的帮助是很大的,在.Net中制作控件相对于VB可能略微复杂一点,但是效果要好很多,在我们现有的项目中原先的Panel控件完全是结合图片+Label来制作的,灵活性和资源利用率要差很多,采用GDI+来绘制控件,效果和质量要好很多。看这段代码应该对组件的制作和GDI+能有更好的理解和认识。
在自己仿照的编写过程中,基本上是看代码和帮助来完成的,发生了两个很笨的事情,一个是设计完组件,没有编译便想使用,结果控件无法使用,所有如果在项目中控件修改了,至少要编译一次在使用。另一个是设计完的控件找不到,后来在工具箱中找到我得用户控件才找到,笨呀.