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

gLabel - 带有特效的自定义标签 (VB.NET)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (87投票s)

2010 年 7 月 20 日

CPOL

6分钟阅读

viewsIcon

266244

downloadIcon

12189

内置了鼠标悬停、阴影、外发光和脉冲发光等效果的标签控件。

gLabel/gLabel.png

引言

我一直在研究一种带有内置阴影的自定义标签控件,这样我就不必分层显示单独的标签或多次将文本绘制到 `Graphics` 对象。在阅读了黄绍文的优秀文章 轮廓文本 [^] 后,我知道我找到了我真正需要的东西。仅仅通过堆叠越来越宽的画笔来获得发光效果的简洁性非常棒。我希望有一天能实现他的更多想法,但目前还没有时间将其转换为 VB.NET。总有一天……

和往常一样,最初只是为了满足需求而设计的简单控件,随着我想到各种“如果……怎么办”的可能性而不断发展。静态轮廓/阴影标签获得了可点击的鼠标悬停选项,该选项扩展为跑马灯进度条的脉冲替代方案……

什么是 `gLabel`?简单来说,它是一个扩展的 `Label`,或者换句话说,是一个继承 `Label` 并覆盖 `OnPaint` 事件以赋予其全新外观的自定义控件。

特点

  • 纯色或混合填充颜色
  • 轮廓文本
  • 外发光高亮
  • `MouseOver` 发光颜色
  • 脉冲发光选项
  • 文本阴影
  • 自动调整
  • 复选框和单选按钮行为选项

控件属性

以下是主要属性列表

如果为 `True`,则将文本调整到控件的边界;如果为 `False`,则使用字体大小绘制文本

处理背景框区域的外观

使用纯色或自定义颜色混合

要应用哪种渐变填充

绘制实际文本的颜色或多种颜色

发光颜色从文本向外延伸的距离

如果 `GlowState` 为 `true`,则发光的颜色

如果 `FeatherSate` 为 `True`,则使发光颜色渐变

发光颜色的强度

如果 `MouseOver` 为 `true`,则绘制发光的颜色

如果 `Pulse` 为 `true`,则使 `GlowColor` 淡入淡出

如果 `ShadowState` 为 `true`,则按偏移量绘制阴影

  • 自动调整
  • BackColor、Border、BorderColor、BorderWidth
  • FillType
  • FillTypeLinear
  • `ForeColor`、`ForeColorBlend`
  • Glow
  • `GlowColor`、`GlowState`
  • FeatherState
  • Feather
  • `MouseOver`、`MouseOverColor`
  • `Pulse`、`PulseSpeed`
  • `ShadowState`、`ShadowColor`、`ShadowOffset`

UITypeEditor

`ForeColorBlend` 使用自定义的 `BlendTypeEditor`。有关 `UITypeEditor` 和 `ControlDesigner` 的详细说明,请参阅 UITypeEditorsDemo[^]。

使用 gLabel

像普通 `Label` 一样将 `gLabel` 拖放到窗体上。AutoSize 被隐藏,因此请调整控件大小以适应 `FontSize`,或将 `AutoFit` 设置为 `True` 以使文本适应控件。

关注点

首先,透明背景的行为就像标准的 `Label` 控件一样。我尝试使用 `Protected Overrides ReadOnly Property CreateParams()` 的真透明背景方法,但闪烁非常严重,所以我将其删除了。

接下来介绍有效的部分。与任何控件一样,绘制由一系列层组成。第一个当然是背景。这在 `Protected Overrides Sub OnPaintBackground` 事件中进行。如果 `BackColor` 为 `Transparent`,则让 `MyBase` 处理它。否则,我根据其 `Enabled` 状态获取背景颜色。

Protected Overrides Sub OnPaintBackground( _
    ByVal pevent As System.Windows.Forms.PaintEventArgs)
        
    If Me.BackColor = Color.Transparent Then
        MyBase.OnPaintBackground(pevent)
    Else
        pevent.Graphics.Clear(EnabledColor(Me.BackColor))
    End If
End Sub

其余层都在 `Protected Overrides Sub OnPaint` 事件中,并将根据每个层的状态属性进行绘制。

在开始介绍绘制层之前,让我首先解释一下发光过程,因为它在这里被多次使用。

Glow

发光是沿着字母轮廓的渐变。渐变在靠近字母边缘时较暗,随着距离的增加而变亮。在 `Color` 结构 ARGB 中,A 是 Alpha 值或您可以透过它的程度。该值范围从 0 到 255,其中 0 表示完全透明,255 表示您无法透视的纯色。

如果您用 `Color.FromARGB(125, Color.Red)` 绘制一个正方形,然后用 `Color.FromARGB(125, Color.Blue)` 绘制另一个正方形并与其部分重叠,则不重叠的部分将是浅红色或蓝色。重叠的部分将混合成紫色并更不透明。现在,使用相同的颜色绘制两个正方形,并执行相同的操作。重叠部分是蓝色,其他部分是浅蓝色,并且更半透明。

gLabel/AlphaBlend1.png

现在让我们看 6 个蓝色矩形,每个矩形都比前一个宽。当您对齐左边缘时,它会形成一个从深到浅的渐变混合。

gLabel/AlphaBlend2.png

进一步发展这个想法,使每个连续的矩形都比前一个更透明一些,这样看起来会更好。

gLabel/AlphaBlend3.png

将此想法与 `Pen` 结合使用,其中矩形的宽度对应于 `Pen` 的宽度。使用 `String` 的 `GraphicsPath`,循环您想要创建发光效果的次数。然后填充路径以创建文本的正面。

For i As Integer = 1 To _Glow Step 2
    Dim aGlow As Integer = CInt(_Feather - _
      ((_Feather / _Glow) * i))
    Using pen As Pen = New Pen(Color.FromArgb( _
      aGlow, EnabledColor(gColor)), i)
        pen.LineJoin = LineJoin.Round
        g.DrawPath(pen, path)
    End Using
Next i

g.FillPath(New SolidBrush(Me.ForeColor), path)

OnPaint

好的,回到各层。首先,为了绘制阴影,我获取文本的 `GraphicsPath`,并使用 `Matrix` 将 (X, Y) 坐标按 `ShadowOffset` 属性进行 `Translate`。然后使用上述发光过程绘制阴影。

接下来是实际的发光文本。根据 `MouseOver` 属性确定发光颜色。使用上述发光过程,但带有这些选项:`FeatherState`、`Enabled` 和 `Pulse`。最后,使用填充属性填充文本路径。

最后一层是边框,它只是使用边框属性在 `gLabel` 的矩形区域周围绘制一个矩形。

自动调整

标准标签有一个 `AutoSize` 属性,但它只是根据文本长度调整宽度。我希望文本填充整个区域。为了使文本路径适应控件的大小,我使用 `Matrix` 变换 `GraphicsPath`。

让我们看看何时需要将标签放在特定区域内。标准 `Label` 中的长文本将被截断。减小 `Font.Size` 以使文本适应有时会使高度太小而难以阅读。调整文本会独立于高度来压缩宽度。

gLabel/LongText.png

为此,首先创建一个您希望文本适合的区域的 `Rectangle`。

Dim target As New Rectangle( _
    0, 0, _
    Me.ClientSize.Width, _
    Me.ClientSize.Height)

然后获取目标矩形的 `PointF` 表示。

Dim target_pts() As PointF = { _
    New PointF(target.Left, target.Top), _
    New PointF(target.Right, target.Top), _
    New PointF(target.Left, target.Bottom) _
    }

使用 `GraphicsPath AddString` 获取接近目标矩形大小的文本路径。然后使用 `GetBounds` 获取路径周围的矩形。

path.AddString(Me.Text, Me.Font.FontFamily, Me.Font.Style, _
               target.Height, New PointF(0, 0), sf)
Dim text_rectf As RectangleF = path.GetBounds() 

然后使用 `Matrix` `Transform` `Graphics` 对象,使文本适应目标矩形。

g.Transform = New Matrix(text_rectf, target_pts)

为了使 `GlowColor` 脉冲,使用 `Timer` 来增加和减少 `Feather` 值。

Private Sub Pulser_Tick(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles Pulser.Tick
    _PulseAdj += PulseDirection
    If _Feather - _PulseAdj < 10 _
      OrElse _Feather - _PulseAdj > _Feather Then
        PulseDirection *= -1
        _PulseAdj += PulseDirection
    End If
    Me.Invalidate()
End Sub

ColorFillBlend 的 TypeConverter

版本 1.0.8 新增,`ForeColorBlend` 的 `TypeConverter` 可以将混合的 `String` 表示形式转换为 `cBlendItems`,以允许更精确的调整,并轻松地将混合从一个 `gLabel` 复制到另一个。

CheckType:复选框和单选按钮行为

`CheckType` 属性可以设置为 `Label`、`Check` 或 `Radio`。当单击时,`Label` 的行为像标准标签。当单击时,`Check` 会设置 `Checked` 属性和颜色,独立于其他 `gLabel`。当单击时,`Radio` 会将 `Checked` 属性设置为 `True`,并将同一父级上设置为 `Radio` 类型的其他所有 `gLabel` 设置为 `False`。

当 `GlowMatchChecked` 属性为 `True` 时,`GlowState` 将随 `Checked` 属性而改变。

花哨的标签完成。

历史

  • 版本 1.0.5 - 2010 年 7 月
    • 首次发布版本
  • 版本 1.0.6 - 2011 年 1 月
    • 增加了填充支持
    • 增加了 `TextWordWrap` 属性
    • 增加了 AutoEllispis 支持
  • 版本 1.0.7 - 2011 年 3 月
    • 增加了 `MouseOverForeColor` 属性
    • 增加了 `Checked` 属性
    • 增加了 `CheckedColor` 属性
    • 增加了 CheckedToggleState 方法
  • 版本 1.0.8 - 2012 年 1 月
    • 增加了 `BlendItemsConverter`
    • 清理了默认值
    • 增加了 `CheckedType` 属性
© . All rights reserved.