chart控件做实时曲线显示_玩转图形:VB.net GlassLabel控件

不久前,我正在开发Windows Forms应用程序,我需要一个特殊的具有反射(玻璃)效果的标签控件,以一种时尚的方式显示一些标题。

a3e7cedd49ed4b4f9b601a7e422f251f.png

我一直很喜欢图形处理,但是重新发明轮子从来都不是太聪明,所以我要做的第一件事就是使用Google来满足我所有需求的控件。不幸的是(或没有?)我什么也没找到。我一直在寻找一种类似标签的控件,该控件可以像玻璃一样自动反映其文本内容。当然,反射的文本必须显示为半透明。也欢迎所有其他控制功能。就像我说的,没有发现任何类似的事件。
嗯...对此深思熟虑,我意识到自己打造自己并不困难,所以动手吧!首先,我写了我的需求列表(一旦它们突然出现,我就添加了越来越多的东西!)。最终需求列表如下:

它必须是真正的标签控件。

它将显示所绘制文本的反射或玻璃效果。

控件的背景可以填充纯色或渐变色。

控件的文本也可以用纯色或渐变色填充。

文本可以绘制(或不绘制)具有可配置宽度的纯色轮廓。

透明度级别也必须是可配置的。

我最后得到了上面看到的内容。还不错吧?幸运的是,我可以说已经实现了所有目标。
完成后,我认为写一篇专注于该控件图形工作的文章将是一个好主意。因此,我将评论我所做的事情以及为什么这样做,并以控件的完整代码清单结束我的文章。

1.如果是标签,则为标签

如我的需求列表中所述,该控件必须是真正的标签控件。因此,我开始创建一个新类,并从标准WinForms Label控件继承它。

Public Class GlassLabel    Inherits System.Windows.Forms.LabelEnd Class

我对Label控件的标准行为做了两个小的更改。首先,默认情况下,Label控件是自动调整大小的。但是对于我的控件来说,背景非常重要,因为它允许渐变,因此我决定删除控件的自动调整大小功能。这是通过覆盖AutoSize属性完成的:

'The AutoSize property has been overridden to achieve the control'not to be auto-sized.Public Overrides Property AutoSize() As Boolean    Get        Return MyBase.AutoSize    End Get    Set(ByVal value As Boolean)        MyBase.AutoSize = False    End SetEnd Property

我所做的第二个更改是消除了将文本放置在控件(TextAlign)上的任何位置的可能性,因此在我的控件中,文本将始终水平和垂直居中。

'The TextAlign property has been overridden to achieve the control text'be aligned always at Middle-Center.Public Overrides Property TextAlign() As System.Drawing.ContentAlignment    Get        Return MyBase.TextAlign    End Get    Set(ByVal value As System.Drawing.ContentAlignment)        MyBase.TextAlign = ContentAlignment.MiddleCenter    End SetEnd Property

最后一点并不是真正必要的,因为我在控件上进行了所有绘制,因此我确定了文本出现的确切位置。实际上,此更改仅在“属性”窗口中有用,在该窗口中,您将始终在TextAlign属性中看到TopCenter,并且将无法对其进行更改。但是,即使没有这段代码,控件也会看起来完全一样。
最后,我完全重写了OnPaint方法,因为我不希望.Net绘制控件-我想根据自己的要求进行操作。确实,所有工作都是通过OnPaint重写方法完成的:

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)    'All the painting work is done here.    ...End Sub

2.渐变

该控件支持背景和文本的渐变。借助GDI +,渐变是.Net中最简单的操作之一。实际上,.Net为我们提供了一个名为LinearGradientBrush的自定义画笔,我们只需要为其提供绘制矩形(需要计算渐变的步数),开始和结束颜色以及渐变的方向即可(水平,垂直或对角线)。就这么简单:

Dim gradBrush As LinearGradientBrush = New LinearGradientBrush(rectangle, color1, color2, direction)Graphics.FillRectangle(gradBrush, rectangle)

当然,您可以将渐变画笔与矩形,椭圆,多边形,区域,路径等配合使用。
在GlassLabel控件的完整列表中,您会找到一些使用渐变的代码,并且您会发现使用渐变的简单性使用它们。

3.大纲

有一些方法可以将文本绘制到Graphics对象中。最基本的方法是使用DrawString方法,该方法带有一些参数(文本,字体,大小,位置...),并使用所需的画笔绘制文本。
但是对于大纲要求,我需要比DrawString提供的功能更多。所以我用了GraphicsPath目的。正如MSDN所说,GraphicsPath代表一系列连接的直线和曲线。应用程序使用路径绘制形状的轮廓,填充形状的内部以及创建剪切区域。最棒的是,GraphicsPath对象提供了它自己的AddString方法,因此我们只需要在GraphicsPath上调用AddString即可创建一个概述所传递字符串的路径。之后,您既可以绘制字符串轮廓,也可以填充其内容。

Dim path As GraphicsPath = New GraphicsPathpath.AddString(text, fontFamily, fontStyle, emSize, clippingRect, stringFormat)Graphics.DrawPath(pen, path)Graphics.FillPath(brush, path)

在GlassLabel控件的完整清单中,您将找到一些我在其中使用GraphicsPath的代码,并且您将看到如何使用它们。

4.反思

显而易见,要求的难度更大的是玻璃或反射效果。与GDI +中的几乎所有内容一样,有许多方法可以做到这一点。但是我认为我可能使用了所有方法中最简单的方法。
图形对象支持一系列可能会影响其大小,旋转角度等的变换。一旦将此变换中的一个应用于图形对象,在该对象上完成的所有绘制工作都会受到所完成的变换的影响。这种转换可以是累积的,这为我们提供了一种非常强大的处理图形的机制。
在这种情况下,我做了一个非常简单的转换:我对图形对象“说”所有画都必须受到比例转换的影响。所应用的比例对于水平轴为1(因此没有变换),对于垂直轴为-1(因此大小没有变换,但垂直反射)。就这么简单。您可以在本文结尾的代码清单中找到完整的示例。

Graphics.ScaleTransform(1, -1)

此后,我在该图形对象上绘制的所有内容(文本,形状等)将显示为垂直反射。

完整清单

好吧,信不信由你,使用这几个GDI +对象,就可以完成所有工作。这是我的GlassLabel控件的完整清单代码。该代码已被很好地注释,我认为您可以轻松地遵循它。
作为进一步工作的建议,最好不要重写TextAlign属性,并使其按预期方式在控件中工作,然后重新计算每个可能值的位置。另一个有趣的挑战是找到一种方法来透视显示反射效果。

Imports System.DrawingImports System.Drawing.Drawing2DImports System.Drawing.ImagingPublic Class GlassLabel    Inherits System.Windows.Forms.Label    'Variables to hold properties values    'Each initialization values represent the default value for the property    Private m_BackGradientColor1 As Color = Color.Black    Private m_BackGradientColor2 As Color = Color.White    Private m_BackGradientMode As LinearGradientMode = LinearGradientMode.Horizontal    Private m_BackGradient As Boolean = False    Private m_Alpha As Integer = 100    Private m_ForeGradientColor1 As Color = Color.Purple    Private m_ForeGradientColor2 As Color = Color.White    Private m_ForeGradientMode As LinearGradientMode = LinearGradientMode.Vertical    Private m_ForeGradient As Boolean = False    Private m_OffsetY As Integer = 0    Private m_OutlineColor As Color = Color.White    Private m_OutlineWidth As Integer = 0    'This property get/set text outline border color    Public Property OutlineColor() As Color        Get            Return m_OutlineColor        End Get        Set(ByVal value As Color)            m_OutlineColor = value            Me.Invalidate()        End Set    End Property    'This property get/set text outline border width    'If set to zero, then it's not outline    Public Property OutlineWidth() As Integer        Get            Return m_OutlineWidth        End Get        Set(ByVal value As Integer)            m_OutlineWidth = value            Me.Invalidate()        End Set    End Property    'This property get/set an integer value that represents    'the number of pixels that must close up the normal text and    'the reflected text. As MeasureString considers special characters    'and glyphos, it returns vertically an extra space. The OffsetY    'property tells the control to dispose N pixels of space between    'the drawn texts.    Public Property OffsetY() As Integer        Get            Return m_OffsetY        End Get        Set(ByVal value As Integer)            m_OffsetY = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating if draw the texts    'using a gradient fill (true) or a solid fill (false)    Public Property ForeGradient() As Boolean        Get            Return m_ForeGradient        End Get        Set(ByVal value As Boolean)            m_ForeGradient = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating the direction of    'the texts gradient fill    Public Property ForeGradientMode() As LinearGradientMode        Get            Return m_ForeGradientMode        End Get        Set(ByVal value As LinearGradientMode)            m_ForeGradientMode = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating the second color of    'the texts gradient fill    Public Property ForeGradientColor2() As Color        Get            Return m_ForeGradientColor2        End Get        Set(ByVal value As Color)            m_ForeGradientColor2 = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating the first color of    'the texts gradient fill    Public Property ForeGradientColor1() As Color        Get            Return m_ForeGradientColor1        End Get        Set(ByVal value As Color)            m_ForeGradientColor1 = value            Me.Invalidate()        End Set    End Property    'This property get/set a value that represents the level of    'transparency in the reflected text. Values must be between 0 and 255.    'The lower value, reflected text is more transparent.    'The higher value, more opaque.    Public Property Alpha() As Integer        Get            Return m_Alpha        End Get        Set(ByVal value As Integer)            m_Alpha = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating if draw the control's background    'using a gradient fill (true) or a solid fill (false)    Public Property BackGradient() As Boolean        Get            Return m_BackGradient        End Get        Set(ByVal value As Boolean)            m_BackGradient = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating the direction of    'the control's background gradient fill    Public Property BackGradientMode() As LinearGradientMode        Get            Return m_BackGradientMode        End Get        Set(ByVal value As LinearGradientMode)            m_BackGradientMode = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating the second color of    'the control's background gradient fill    Public Property BackGradientColor2() As Color        Get            Return m_BackGradientColor2        End Get        Set(ByVal value As Color)            m_BackGradientColor2 = value            Me.Invalidate()        End Set    End Property    'This property get/set a value indicating the first color of    'the control's background gradient fill    Public Property BackGradientColor1() As Color        Get            Return m_BackGradientColor1        End Get        Set(ByVal value As Color)            m_BackGradientColor1 = value            Me.Invalidate()        End Set    End Property    'The AutoSize property has been overridden to achieve the control    'not to be auto-sized.    Public Overrides Property AutoSize() As Boolean        Get            Return MyBase.AutoSize        End Get        Set(ByVal value As Boolean)            MyBase.AutoSize = False        End Set    End Property    'The TextAlign property has been overridden to achieve the control text    'be aligned always at Middle-Center.    Public Overrides Property TextAlign() As System.Drawing.ContentAlignment        Get            Return MyBase.TextAlign        End Get        Set(ByVal value As System.Drawing.ContentAlignment)            MyBase.TextAlign = ContentAlignment.MiddleCenter        End Set    End Property    'All the paintint work is done here.    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)        With e.Graphics            '*** Apply high-quality properties to the graphics object ************************            .CompositingQuality = CompositingQuality.HighQuality            .InterpolationMode = InterpolationMode.HighQualityBicubic            .PixelOffsetMode = PixelOffsetMode.HighQuality            .SmoothingMode = SmoothingMode.HighQuality            .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias            '*** Draw the control's background ***********************************************            If Me.BackGradient Then                'The background must show a gradient, so we need to create a gradient brush                'and fill the control's background rectangle with this gradient                Using bkg As LinearGradientBrush = New LinearGradientBrush(e.ClipRectangle, Me.BackGradientColor1, Me.BackGradientColor2, Me.BackGradientMode)                    .FillRectangle(bkg, e.ClipRectangle)                End Using            Else                'The background is a solid color. The Clear method of the Graphics object                'let us to choose a color to clear the background.                .Clear(Me.BackColor)            End If            '*********************************************************************************            '*** Create and draw the normal (not reflected) text *****************************            'Get the text width & height            Dim width As Single = .MeasureString(Me.Text, Me.Font).Width            Dim height As Single = .MeasureString(Me.Text, Me.Font).Height            'Create a rectangle that delimites the position & size of the text drawn            'The x position must be (control width - text width) / 2, so the text will be            'horizontally centered            Dim xpos As Single = (e.ClipRectangle.Width - width) / 2            'The y position must be also vertically centered, so we start from            '(control height - text height) / 2            'But below the normal text will be the reflected text, so must offset to top            'the half of text height            'Additionally, MeasureString give us extra space reserved for tall glyphos,            'so must consider the OffsetY value to delete this extra space, so must offset            'to bottom the half of OffsetY value            Dim ypos As Single = ((e.ClipRectangle.Height - height) / 2) - (height / 2) + (Me.OffsetY / 2)            'Finally, create the rectangle from x,y pos and width & height of the text            Dim originalRect As New RectangleF(xpos, ypos, width, height)            'Draw the original string. We'll use a GraphicsPath object instead            'using DrawString directly, because GraphicsPath will let us draw an            'outline border to the text            'Create the path            Dim path As GraphicsPath = New GraphicsPath            'Add the string to the path. Because GraphicsPath's AddString method            'uses emSize (the height of the em square box that bounds the character)            'instead of Point, we must convert out font's Point size to emSize using            'this formula: (Vertical Resolution / 72) * Font's Point Size            path.AddString(Me.Text, Me.Font.FontFamily, Me.Font.Style, (.DpiY / 72) * Me.Font.Size, originalRect, StringFormat.GenericDefault)            'If and outline must be drawn, draw it            If Me.OutlineWidth > 0 Then                Using p As Pen = New Pen(Me.OutlineColor, Me.OutlineWidth)                    .DrawPath(p, path)                End Using            End If            'Create the brush to fill the text            Dim fill As Brush            If Me.ForeGradient Then                'Text must be filled with a gradient brush                fill = New LinearGradientBrush(originalRect, Me.ForeGradientColor1, Me.ForeGradientColor2, Me.ForeGradientMode)            Else                'Text must be filled with a solid brush                fill = New SolidBrush(Me.ForeColor)            End If            'Fill the text and destroy the brush            .FillPath(fill, path)            fill.Dispose()            'The GraphicsPath object won't be needed anymore            path.Dispose()            'From this point we must deal with reflected text. So it's a good idea to            'save the current state of our graphics object. What is really saved is the            'state of the objects (transformations applied, etc), not the drawings done            'until here.            Dim state As GraphicsState = .Save            'Reset the transformations done until here so we start from a "fresh clean"            'graphics object state.            .ResetTransform()            'ScaleTransform will set the graphics object into a state in which all the            'drawings done after the instruction will be affected by the scaling done.            'As we use 1 for horizontal value, the drawings will be not changed in the            'horizontal plane. But as we use -1 for the vertical value, all the drawings            'will be vertically inverted (the reflection effect that we want).            .ScaleTransform(1, -1)            'Now, as we did for the normal text, we'll create a rectangle that delimites            'the position and size of the reflected text            'The x-position must not be changed, as it is the same (horizontally centered)            'The y-pos must be vertically centered, so we start from            '(control height - text height) / 2            'From there, as we did with normal text, we must offset the half of the text height            '(in this case, offset to top)            'Also must offset the OffsetY value, to top too            'BUT we must remember that this will be drawn over a transformed (Scaled)            'graphics object, so must invert all signs (for example, offset to bottom instead            'to top)            ypos = (((((e.ClipRectangle.Height - height) / 2) + (height / 2)) * -1) - height) + (Me.OffsetY / 2)            'Create the rectangle            Dim reflectedRect As New RectangleF(xpos, ypos, width, height)            'Create the path to hold the text            Dim reflectedPath As GraphicsPath = New GraphicsPath            'Add the string to the path            reflectedPath.AddString(Me.Text, Me.Font.FontFamily, Me.Font.Style, (.DpiY / 72) * Me.Font.Size, reflectedRect, StringFormat.GenericDefault)            'Draw the outline, if it applies            If Me.OutlineWidth > 0 Then                'Note that we apply alpha transparency to the outline. If not, reflected                'text's outline will appear too much "solid"                Using p As Pen = New Pen(Color.FromArgb(Me.Alpha, Me.OutlineColor), Me.OutlineWidth)                    .DrawPath(p, reflectedPath)                End Using            End If            'Create the brush to fill the reflected text            If Me.ForeGradient Then                'We must apply Alpha transparency on both gradient colors                fill = New LinearGradientBrush(reflectedRect, Color.FromArgb(Me.Alpha, Me.ForeGradientColor1), Color.FromArgb(Me.Alpha, Me.ForeGradientColor2), Me.ForeGradientMode)            Else                'Apply Alpha to solid color too                fill = New SolidBrush(Color.FromArgb(Me.Alpha, Me.ForeColor))            End If            'Draw the text (it will be automatically reflected because of the Scale            'transformation applied)            .FillPath(fill, reflectedPath)            'Destroy objects that are no more needed            fill.Dispose()            reflectedPath.Dispose()            'Restore the Graphics object state (eliminate transformations, so if we drew            'anymore from here will not be reflected)            .Restore(state)            '*********************************************************************************        End With    End SubEnd Class

我希望大家发现此控件有用。随时在您的应用程序中使用它,并进行修改以方便使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值