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

扁平化 ComboBox!

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.24/5 (17投票s)

2002 年 6 月 14 日

5分钟阅读

viewsIcon

279413

downloadIcon

3531

VB.NET 中的扁平风格组合框

扁平化你的组合框

在 .NET 中,微软提供了许多供我们使用的东西。它们能够像标准化大多数控件的 Text 和 Name 属性一样,这样做很方便。然而,关于扁平化外观的故事又是什么呢?

有些控件通过 FlatStyle 属性或 Border 属性拥有扁平外观。我喜欢扁平外观,并且一直将其用于我所有的控件,除了一个——组合框。你知道当一个数据录入表单中所有的文本框、复选框、单选按钮、命令按钮等都呈扁平状,而它的组合框却是 3D 的时候,看起来有多么奇怪吗?你可能知道,这也是你为什么会来这里的原因……

这个项目只不过是一个继承自组合框的简单组合框。常规组合框的所有事件和属性都存在。它甚至支持数据绑定。最棒的是,它是扁平的。

扁平外观是通过子类化实现的,这是一个很棒的面向对象概念,新的 VB.NET 开发者正在逐渐适应。有 6 个被重写的方法。

    
    Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
    Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
    Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
    Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
    Protected Overrides Sub OnMouseHover(ByVal e As System.EventArgs)
    Protected Overrides Sub WndProc(ByRef m As Message)

焦点和输入方法所做的几乎都是同一件事。它们调用 MyBase.OnMethod(这会触发适当的事件),设置我们将用于绘制背景的画笔颜色,并调用 `Me.Invalidate()`,这将导致控件重新绘制。

真正的工作是由 WndProc 方法完成的。出于我尚未弄清楚的原因,组合框不会调用基类的 OnPaint。控件实际上是通过窗口消息绘制的。我使用 Select Case 来评估消息。Case &HF (15) 是 paint 方法的值。它来自窗口消息常量 `WM_PAINT`。

一旦我们捕获到 WM_PAINT 消息,就可以开始工作了。我只需根据前面提到的其中一个事件设置的颜色来绘制背景色。(例如,OnGotFocus 将颜色设置为 `SystemColors.Highlight`,该颜色在 System.Drawing 命名空间中找到)。我通过创建 Graphics 对象的句柄并调用 `FillRectangle` 方法来完成此操作。

      Dim g As Graphics = Me.CreateGraphics
      g.FillRectangle(BorderBrush, Me.ClientRectangle)

基类将在该背景填充之上绘制一个编辑框,从而为控件提供高亮效果。接下来是绘制下拉按钮的矩形。这总是有一个固定的宽度和位置,与组合框控件的宽度相关。基控件就是这样工作的,这也使得定位下拉箭头的绘制区域更加容易。

Dim rect As Rectangle = New Rectangle(Me.Width - 15, 3, 12, _
                                      Me.Height - 6)
      g.FillRectangle(DropButtonBrush, rect)

最后一步是绘制下拉箭头。这是通过创建并填充一个路径来完成的。Drawing2D.GraphicsPath 对象提供了一种以“自由”方式绘制线条的方式。这些线条始终是连接的。路径会自行关闭,从最后一个映射点到第一个点形成一条直线。这有点像用一个旧的“画图板”画画,笔永远不会离开绘图表面。因此,要绘制一个三角形,只需要画两条线。

在下面的代码中,我声明了三角形的 3 个点(相对于控件的垂直中心)。然后我画了两条线。一条线从左上角到右上角,另一条线从右上角到底部。

 
 Dim pth As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
 Dim TopLeft As PointF = New PointF(Me.Width - 13, (Me.Height - 5) / 2)
 Dim TopRight As PointF = New PointF(Me.Width - 6, (Me.Height - 5) / 2)
 Dim Bottom As PointF = New PointF(Me.Width - 9, (Me.Height + 2) / 2)

 pth.AddLine(TopLeft, TopRight)
 pth.AddLine(TopRight, Bottom)

然后我设置了 Graphics 对象的平滑模式属性,以便三角形看起来更清晰。

g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality

每当我们填充某些东西时,都需要使用画笔。Fill 方法的签名要求提供一个 Brush,但你无法创建 Brush 的实例。Brush 类是抽象的,意味着必须继承它才能使用。怎么办?实心填充的最佳选择是使用 SolidBrush 类。这可能很难弄清楚,就像我刚开始接触 GDI+ 时一样。

为了确定填充三角形的颜色,我检查了 DroppedDown 属性。我注意到组合框控件的箭头根据是否已下拉而呈现两种不同的颜色。

If Me.DroppedDown Then
    ArrowBrush = New SolidBrush(SystemColors.HighlightText)
Else
    ArrowBrush = New SolidBrush(SystemColors.ControlText)
End If

最后,是时候填充三角形了。

g.FillPath(ArrowBrush, pth)

瞧!完成了。一个扁平的组合框。我在控件中添加了一个按钮颜色的属性,以便有创意的 GUI 设计师可以拥有更多的灵活性。它的大部分代码都很简单,但我确实想指出关于属性设置语句的一点。

    Public Property ButtonColor() As Color
        Get
            Return _ButtonColor
        End Get
        Set(ByVal Value As Color)
            _ButtonColor = Value
            DropButtonBrush = New SolidBrush(Me.ButtonColor)
            Me.Invalidate()
        End Set
    End Property

请注意对 `Me.Invalidate()` 的调用。这会导致控件自行重绘。现在,在设计时,当属性更改时,设计器将显示新的按钮颜色。

这个项目简短而精致。但其中有几个好东西可以学习。使用 GDI+ 绘制自定义控件和子类化是 .NET 中两个非常重要的学习内容。我希望这篇文章能帮助你理解 FlatCombo 代码的分解,并帮助你更深入地理解这些重要的概念。

我之前曾将这个项目从一个 C# 项目转换而来。如果你下载源代码,你会看到旧版本。它在绘制方式上存在一些奇怪的 bug。而且也过于复杂。我想把它留下来,以防你想看到不同的解决方案。

© . All rights reserved.