vb.net 图形控件_玩转图形:VB.net GlassLabel控件

vb.net 图形控件

A while ago, I was working on a Windows Forms application and I needed a special label control with reflection (glass) effect to show some titles in a stylish way.

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

The GlassLabel control at work.

Mmmm... thinking deeply about it I realized that it would not be too difficult to build my own, so hands on!  First of all, I wrote my requirements list (and I added more and more things as soon as they popped into my head!).  The final requirement list was like this:

嗯...对此深思熟虑,我意识到自己打造自己并不困难,所以动手吧! 首先,我写了我的需求列表(一旦它们出现在我的脑海里,我就添加了越来越多的东西!)。 最终需求列表如下:

It must be a true label control.

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



It will show a reflection or glass effect of the text drawn.

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



The control's background can be filled with solid or gradient colors.

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



The control's text can be filled with solid or gradient colors, too.

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



The text can draw (or not) a solid-color outline with configurable width.

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



The level of transparency must be configurable, too.

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



Once done, I thought that writing an article focusing on the graphics work for this control would be a good idea. So I will comment on what I've done and why I did it and will finish my article with the complete code listing of the control.

完成后,我认为写一篇专注于该控件图形工作的文章将是一个好主意。 因此,我将评论我所做的事情以及为什么这么做,并以控件的完整代码清单结束我的文章。

1.如果是标签,则为标签 (1. If it's a Label, then it's a Label)

As said in my requirements list, the control must be a true label control. So I started creating a new class and inheriting it from the standard WinForms Label control.

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

Public Class GlassLabel
    Inherits System.Windows.Forms.Label
End Class
'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

Finally, I have overridden completely the OnPaint method, because I don't want .Net to draw the control -- I want to do it myself with my requirements. Really, all the work is done in the OnPaint overridden method:

最后,我完全重写了OnPaint方法,因为我不希望.Net绘制控件-我想根据自己的需要进行操作。 确实,所有工作都是通过OnPaint重写方法完成的:

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

2.渐变 (2. Gradients)

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

In the complete listing of GlassLabel control you'll find some code in which I use gradients, and you'll see how easy is to use them.

在GlassLabel控件的完整列表中,您将找到一些我在其中使用渐变的代码,并且您会看到使用它们的简便性。

3.大纲 (3. Outline)

有一些方法可以将文本绘制到Graphics对象中。 最基本的方法是使用DrawString方法,该方法带有一些参数(文本,字体,大小,位置...),并使用所需的画笔绘制文本。

But for the outline requirement I needed more functionality than DrawString offers. So I used GraphicsPath object. As MSDN says, GraphicsPath represents a series of connected lines and curves. Applications use paths to draw outlines of shapes, fill the interiors of shapes, and create clipping regions. Best of all, the GraphicsPath object provides with it's own AddString method, so we just need to call AddString on the GraphicsPath and it creates a path that outlines the string passed. After that, you can both draw the string outline or fill its contents.

但是对于大纲要求,我需要比DrawString提供的功能更多。 所以我用了GraphicsPath对象。 正如MSDN所说,GraphicsPath代表一系列连接的直线和曲线。 应用程序使用路径绘制形状的轮廓,填充形状的内部以及创建剪切区域。 最棒的是,GraphicsPath对象提供了它自己的AddString方法,因此我们只需要在GraphicsPath上调用AddString,它会创建一个概述所传递字符串的路径。 之后,您既可以绘制字符串轮廓,也可以填充其内容。

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

4.反思 (4. Reflection)

显而易见,要求的难度更大是玻璃或反射效果。 与GDI +中的几乎所有内容一样,有很多方法可以做到这一点。 但是我认为我可能使用了所有方法中最简单的方法。

A graphics object supports a series of transformations that can affect to his size, rotation angle, etc. Once one of this transformation is applied to a graphics object, all the painting work done over the object is affected by the transformations done. This transformations can be cumulative and that gives us an extremely powerful mechanism to work with graphics.

图形对象支持一系列可能影响其大小,旋转角度等的变换。一旦将此变换中的一个应用于图形对象,在该对象上完成的所有绘制工作都会受到所完成的变换的影响。 这种转换可以是累积的,这为我们提供了一种非常强大的处理图形的机制。

In this case I did a really simple transformation: I "said" to my graphics object that all the painting must be affected by a scale transformation. The scale applied is 1 for the horizontal axis (so no transformation) and -1 for the vertical axis (so no transformation in size but vertically reflected). It's as simple as that. You'll find the complete sample in the code listing at the end of the article.

在这种情况下,我做了一个非常简单的转换:我对图形对象“说”所有画都必须受到比例转换的影响。 对于水平轴,应用的比例为1;对于垂直轴,应用的比例为-1(因此,尺寸没有变化,但垂直反射)。 就这么简单。 您可以在本文结尾的代码清单中找到完整的示例。

Graphics.ScaleTransform(1, -1)

完整清单
(The Complete Listing
)

好吧,信不信由你,使用这几个GDI +对象,就可以完成所有工作。 这是我的GlassLabel控件的完整列表代码。 该代码的注释很好,我认为您可以轻松地遵循它。

As a suggestion for further work, maybe it would be a good idea to not override the TextAlign property and make it work in the control as expected, re-calculating the position for each one of the possible values.  Another interesting challenge would be to find a way to show the reflection effect in perspective.

作为进一步工作的建议,最好不要重写TextAlign属性,并使其按预期方式在控件中工作,然后重新计算每个可能值的位置。 另一个有趣的挑战是找到一种方法来透视显示反射效果。

Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging

Public 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 Sub
End Class

翻译自: https://www.experts-exchange.com/articles/3623/Having-fun-with-graphics-a-VB-net-GlassLabel-control.html

vb.net 图形控件

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值