带渐变色和额外图像的自定义按钮控件 (VB.NET)






4.91/5 (122投票s)
这是一个易于使用的自定义按钮控件,但具有许多视觉设计选项。
引言
CButton
是一个用 VB.NET 编写的简单自定义按钮控件。抱歉,我刚开始时没有意识到“C”前缀是特定于语言的。它只是 Custom Button 的缩写。我不会再让这种事情发生。这是普通 Microsoft 按钮的一个很好的替代方案。
对 3.4 及更早版本的现有用户的重要提示。
从 3.5 版开始,不再需要 DesignerRectTracker 类,并且需要对使用旧控件并即将使用新控件的现有项目进行一些设计器清理。(有关更多详细信息,请参阅下文)
以下是主要功能列表
- 更改按钮的形状
- 调整圆角的圆角矩形
- 纯色和多色填充
- 文本阴影和边距
- 可调的鼠标悬停和点击颜色更改,并带有模拟点击移动
- 普通按钮图像和/或附加的侧边图像
我在 1.2 版中通过添加 UITypeEditors
和 ControlDesigners
来改进了设计时编辑。请参阅 UITypeEditorsDemo[^] 以获得详细解释。这使我能够将某些属性合并到一个属性中,或改进其他属性。
例如
ButtonColorA
、ButtonColorB
和ButtonColorC
被合并到ColorFillBlend
中,允许无限的颜色混合,而不是仅限于三种颜色ButtonColorCenterPoint
和ButtonColorCenterPtOffset
被合并到FocalPoints
中CornerRadius
成为一个可扩展属性Corners
,允许单独调整每个角
背景
这是另一个需要(好吧,老实说,一个普通按钮也可以,但我想要)一个更好看、视觉效果更强的按钮的例子。已经有很多很棒的按钮控件了,但没有我想要的全部功能。基本上,我创建了我想要的功能,然后重写了 OnPaint
来按照我想要的方式绘制它。
控件属性
以下是主要属性列表
形状
按钮是什么形状(矩形、椭圆形、三角形)
ColorFillBlend
渐变填充中使用的颜色
BorderColor
,BorderShow
以不同颜色显示边框
FillType
使用哪种颜色渐变类型(纯色、线性或路径)
FocalPoints
路径渐变类型填充的
CenterPoint
和FocusScales
角点
每个圆角弧的半径
DimFactorHover
,DimFactorClick
鼠标悬停和点击时调整按钮颜色的数字
TextShadow
,TextShadowShow
显示或不显示文本阴影以及阴影的颜色
TextMargin
将文本推离按钮内边缘
TextSmoothingMode
设置 Graphics 对象以获得更美观文本的
TextRenderingHint
SideImage
添加一个可以放置在按钮表面之外的额外图像
填充
将
ButtonArea
的边缘偏移到控件边缘
Using the Code
一旦您按照期望的方式设计了 CButton
,就没有什么复杂的代码了。只需像普通按钮一样使用它。
由于 Click
事件会在您点击控件的任何位置触发,因此我添加了两个新 Events
;1.1 版中的 ClickButtonArea
事件仅在鼠标点击控件的按钮部分时触发,2.0 版中的 SideImageClicked
事件。
'Add a new Click event for only when the ButtonArea or SideImage is Clicked
Public Event ClickButtonArea(ByVal Sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)
Public Event SideImageClicked(ByVal Sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)
Private Sub CButton_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
If MouseDrawState = eMouseDrawState.Down _
Then RaiseEvent ClickButtonArea(Me, New EventArgs)
MouseDrawState = eMouseDrawState.Up
Me.Invalidate(ButtonArea)
End Sub
关注点
控件只是一个将各个部分按正确位置分层处理的过程。有四个主要区域需要跟踪。控件区域、按钮区域、文本区域和图像区域。按钮区域通过控件内边距值从控件区域中减去。文本区域通过文本边距值和图像区域从按钮区域中减去。图像区域基于图像大小。项目根据其布局选项放置到这些区域中。
Protected Overrides Sub _
OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
e.Graphics.TextRenderingHint = _TextSmoothingMode
'Gray the Text and Border Colors if Disabled
Dim bColor, tColor, tsColor As Color
If Enabled Then
bColor = _BorderColor
tColor = ForeColor
tsColor = _TextShadow
Else
bColor = GrayTheColor(_BorderColor)
tColor = GrayTheColor(ForeColor)
tsColor = GrayTheColor(_TextShadow)
End If
Using MyPen As New Pen(bColor)
MyPen.Alignment = PenAlignment.Inset
'Shrink the Area so the Border draws correctly, _
'then trim off the Padding to get the button surface area
ButtonArea = AdjustRect(New RectangleF(0, 0, _
Size.Width - 1, Size.Height - 1), Padding)
'Create the ButtonArea Path
Using gp As GraphicsPath = GetPath()
If BackgroundImage Is Nothing Then
'Color the ButtonArea with the right Brush
Select Case FillType
Case eFillType.Solid
Using br As Brush = New SolidBrush(GetFill)
e.Graphics.FillPath(br, gp)
End Using
Case eFillType.GradientPath
Using br As PathGradientBrush = _
New PathGradientBrush(gp)
Dim cb As New ColorBlend
cb.Colors = GetFillBlend()
cb.Positions = ColorFillBlend.iPoint
br.FocusScales = _
FocalPoints.FocusScales
br.CenterPoint = New PointF( _
Padding.Left + _
ButtonArea.Width * _
FocalPoints.CenterPoint.X, _
Padding.Top + _
ButtonArea.Height * _
FocalPoints.CenterPoint.Y)
br.InterpolationColors = cb
e.Graphics.FillPath(br, gp)
End Using
Case eFillType.GradientLinear
Using br As LinearGradientBrush = _
New LinearGradientBrush( _
ButtonArea, Color.White, Color.White, _
FillTypeLinear)
Dim cb As New ColorBlend
cb.Colors = GetFillBlend()
cb.Positions = ColorFillBlend.iPoint
'MsgBox(cb.Colors.Length & _
cb.Positions.Length)
br.InterpolationColors = cb
e.Graphics.FillPath(br, gp)
End Using
End Select
End If
If MyBase.Focused AndAlso ShowFocus = eFocus.Dot Then
Using focusPen As Pen = New Pen(Brushes.Black, 1) _
With {.DashStyle = DashStyle.Dot}
e.Graphics.DrawPath(focusPen, GetPath(-1, -1))
End Using
End If
If BorderShow Then
e.Graphics.DrawPath(MyPen, gp)
End If
End Using
Dim ipt As PointF = ImageLocation(GetStringFormat(SideImageAlign), _
Size, SideImageSize)
rectSideImage = New Rectangle(CInt(ipt.X), CInt(ipt.Y), _
SideImageSize.Width, SideImageSize.Height)
'Put the SideImage behind the Text
If SideImageBehindText AndAlso SideImage IsNot Nothing Then
If Enabled Then
e.Graphics.SmoothingMode = SmoothingMode.None
e.Graphics.DrawImage(SideImage, ipt.X, ipt.Y, _
SideImageSize.Width, SideImageSize.Height)
Else
ControlPaint.DrawImageDisabled(e.Graphics, _
New Bitmap(SideImage, SideImageSize.Width, _
SideImageSize.Height), _
CInt(ipt.X), CInt(ipt.Y), BackColor)
End If
End If
'Layout the Text and Image on the button surface
SetImageAndText(e.Graphics)
If Not Image Is Nothing Then
If Enabled Then
e.Graphics.DrawImage(Image, Imagept.X, Imagept.Y, _
ImageSize.Width, ImageSize.Height)
Else
ControlPaint.DrawImageDisabled(e.Graphics, _
New Bitmap(Image, ImageSize.Width, ImageSize.Height), _
CInt(Imagept.X), CInt(Imagept.Y), BackColor)
End If
End If
'Draw the Text and Shadow
If TextShadowShow Then
TextArea.Offset(1, 1)
e.Graphics.DrawString(Text, Font, _
New SolidBrush(tsColor), TextArea, GetStringFormat(TextAlign))
TextArea.Offset(-1, -1)
End If
e.Graphics.DrawString(Text, Font, _
New SolidBrush(tColor), TextArea, GetStringFormat(TextAlign))
'Put the SideImage in front of the Text
If Not SideImageBehindText AndAlso Not SideImage Is Nothing Then
If Enabled Then
e.Graphics.SmoothingMode = SmoothingMode.None
e.Graphics.DrawImage(SideImage, ipt.X, ipt.Y, _
SideImageSize.Width, SideImageSize.Height)
Else
ControlPaint.DrawImageDisabled(e.Graphics, _
New Bitmap(SideImage, _
SideImageSize.Width, SideImageSize.Height), _
CInt(ipt.X), CInt(ipt.Y), BackColor)
End If
End If
End Using
End Sub
为了在控件禁用时将其颜色变灰,我使用了两种方法
要使单个颜色变灰,我使用了这个 Function
Function GrayTheColor(ByVal GrayColor As Color) As Color
Dim gray As Integer = _
CInt(GrayColor.R * 0.3 + GrayColor.G * 0.59 + GrayColor.B * 0.11)
Return Color.FromArgb(GrayColor.A, gray, gray, gray)
End Function
使图像变灰,我最初使用了这个 Function
Private Function EnableDisableImage(ByVal img As Image) As Bitmap
If Me.Enabled Then Return img
Dim bm As Bitmap = New Bitmap(img.Width, img.Height)
Dim g As Graphics = Graphics.FromImage(bm)
Dim cm As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {0.5, 0.5, 0.5, 0, 0}, _
New Single() {0.5, 0.5, 0.5, 0, 0}, _
New Single() {0.5, 0.5, 0.5, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
Dim ia As ImageAttributes = New ImageAttributes()
ia.SetColorMatrix(cm)
g.DrawImage(img, New Rectangle(0, 0, img.Width, img.Height), 0, 0, _
img.Width, img.Height, GraphicsUnit.Pixel, ia)
g.Dispose()
Return bm
End Function
在 2.0 版中,我切换到了 ControlPaint
函数,因为我认为图像效果更好。
ControlPaint.DrawImageDisabled(e.Graphics, Me.Image, _
CInt(Imagept.X), CInt(Imagept.Y), Me.BackColor)
圆角、内边距和焦点
3.5 版新增功能,在 ControlDesigner
中添加了 Adorners 和 Glyphs。有关 WinForms 的 Adorners Glyphs Behavior 和 ControlDesigner 的说明,请访问此链接。
圆角、按钮区域(内边距)、文本边距和焦点点都可以在 PropertyGrid
中编辑。这可能有些繁琐且不直观。通过使用 Adorners 和 Glyphs,这些属性可以直接在控件上用鼠标编辑。
ChooseAdorner
选择控件将在控件的右上角附近显示三个按钮。
Corner Adorner
点击 (C)orner 按钮显示五个圆角符号。前后移动四个圆角符号以单独调整每个圆角。移动中心符号以将所有四个圆角调整到相同值。
FocalPoints Adorner
点击 (F)ocalPoints 按钮获取类似于旧版本的 Center 和 FocalScale 符号。仅当 FillType
为 GradientPath
时才有效。控件上会出现一个小的方形和圆形选择器。拖动圆圈移动 CenterPoint
,拖动正方形移动 FocusScales
。按住 Shift 键并单击符号以将 Center 重置为按钮的中间或将 FocusScale
重置为 0
。
Padding Margin Adorner
点击 (P)adding 来调整 ButtonArea (Padding
Property) 和 TextMargin
Property。虚线将标出边距的位置。拖动两侧进行调整。如果两个边距直接重叠,则 Padding 会首先被选择。按住 Shift 键以强制选择 TextMargin
。
.
3.5 版及更高版本的重要升级说明
此控件已存在很长时间,根据下载和评论,已有相当多的人在使用它。Adorner 升级使 DesignerRectTracker 类不再必要。如果您在项目中使用 3.5 版,而之前版本中有一个旧的 CButton
,您将在任何包含旧 CButton
的 Form 中遇到大量错误。
这非常繁琐,但您需要删除所有有错误的代码行,以消除 Form 的 Designer 中对旧跟踪器的所有引用。
如果有人知道更轻松或批量清理这些的方法,我非常乐意知道。
到目前为止,我找到的最快方法是打开一个窗体设计器窗口,搜索 (Ctrl-F) DesignerRectTracker
。然后按 F3 查找,按 Ctrl-L 删除代码行。在我掌握了节奏之后,它进行得相当快。
ColorFillBlend 的 TypeConverter
2.0 版新增功能,ColorFillBlend
的 TypeConverter
可以将混合的字符串表示形式转换为 cBlendItems
,以便进行更精确的调整,并轻松地将混合从一个 cButton
复制到另一个。
历史
- 版本 1.0 - 2008 年 5 月
- 版本 1.1 - 2008 年 7 月
- 更新了“可点击区域”并添加了
ClickButtonArea
事件
- 更新了“可点击区域”并添加了
- 版本 1.2 - 2008 年 9 月
- 更新了属性以使用
UITypeEditors
和ControlDesigner
- 添加了三角形按钮
- 更新了属性以使用
- 版本 1.3 - 2008 年 9 月
- 按钮区域点击修复。鼠标移动时按钮未点击
- 版本 1.4 - 2008 年 10 月
- 添加了启用/禁用功能
- 版本 1.5 - 2008 年 12 月
- 修复了
FocalPoints
和Corners
属性,以便在子属性在PropertyGrid
中更改时立即刷新控件 - 删除了
FocalPoints
的模态UITypeEditor
,并增加了在设计图面上直接调整点
- 修复了
- 版本 1.6 - 2009 年 1 月
- 根据 NfErNo 的建议,添加了助记符键。
- 版本 1.7 - 2009 年 4 月
- 添加了
SendMessage
以实现穿透非按钮区域的点击
- 添加了
- 版本 1.8 - 2009 年 11 月
- 根据 getholdofphil 的建议添加了键盘事件
- 修复了焦点问题
- 版本 1.9 - 2010 年 7 月
- 将禁用图像例程切换为
ControlPaint
方法 - 添加了
TextSmoothingMode
属性 - 添加了
SideImageClicked
事件 - 将
ClickButtonArea EventArgs
更改为MouseEventArgs
以便更轻松地传递鼠标按钮
- 将禁用图像例程切换为
- 版本 2.0 - 2011 年 12 月
- 添加了
IButtonControl
接口以支持PerformClick
和DialogResult
- 为
cBlendItem
类型添加了BlendItemsConverter
- 添加了
- 版本 2.0 - 2013 年 1 月
- 添加了 Visual Studio 2012 版本
- 版本 3.4 - 2015 年 3 月
- 添加了
ShowFocus
属性
- 添加了
- 版本 3.5 - 2015 年 4 月
- 移除了 ControlDesigner Adorner Override,并添加了真正的 Adorners 和 Glyphs(在现有项目中替换 3.4 或更早版本之前,请参阅上面的重要提示。)
- 添加了
ButtonAreaUp
和ButtonAreaDown
- 版本 3.6 2015 年 5 月
- 修复了
SideImage
在MouseUp
/Down
后中断点击的问题
- 修复了