VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > VB.net教程 >
  • 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控件继承它。


  1.  
    Public Class GlassLabel
  2.  
    Inherits System.Windows.Forms.Label
  3.  
    End Class

  1.  
    'The AutoSize property has been overridden to achieve the control
  2.  
    'not to be auto-sized.
  3.  
    Public Overrides Property AutoSize() As Boolean
  4.  
    Get
  5.  
    Return MyBase.AutoSize
  6.  
    End Get
  7.  
    Set(ByVal value As Boolean)
  8.  
    MyBase.AutoSize = False
  9.  
    End Set
  10.  
    End Property

  1.  
    'The TextAlign property has been overridden to achieve the control text
  2.  
    'be aligned always at Middle-Center.
  3.  
    Public Overrides Property TextAlign() As System.Drawing.ContentAlignment
  4.  
    Get
  5.  
    Return MyBase.TextAlign
  6.  
    End Get
  7.  
    Set(ByVal value As System.Drawing.ContentAlignment)
  8.  
    MyBase.TextAlign = ContentAlignment.MiddleCenter
  9.  
    End Set
  10.  
    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重写方法完成的:


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

2.渐变 (2. Gradients)

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

  1.  
    Dim gradBrush As LinearGradientBrush = New LinearGradientBrush(rectangle, color1, color2, direction)
  2.  
    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,它会创建一个概述所传递字符串的路径。 之后,您既可以绘制字符串轮廓,也可以填充其内容。


  1.  
    Dim path As GraphicsPath = New GraphicsPath
  2.  
    path.AddString(text, fontFamily, fontStyle, emSize, clippingRect, stringFormat)
  3.  
    Graphics.DrawPath(pen, path)
  4.  
    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属性,并使其按预期方式在控件中工作,然后重新计算每个可能值的位置。 另一个有趣的挑战是找到一种方法来透视显示反射效果。


  1.  
    Imports System.Drawing
  2.  
    Imports System.Drawing.Drawing2D
  3.  
    Imports System.Drawing.Imaging
  4.  
     
  5.  
    Public Class GlassLabel
  6.  
    Inherits System.Windows.Forms.Label
  7.  
     
  8.  
    'Variables to hold properties values
  9.  
    'Each initialization values represent the default value for the property
  10.  
    Private m_BackGradientColor1 As Color = Color.Black
  11.  
    Private m_BackGradientColor2 As Color = Color.White
  12.  
    Private m_BackGradientMode As LinearGradientMode = LinearGradientMode.Horizontal
  13.  
    Private m_BackGradient As Boolean = False
  14.  
    Private m_Alpha As Integer = 100
  15.  
    Private m_ForeGradientColor1 As Color = Color.Purple
  16.  
    Private m_ForeGradientColor2 As Color = Color.White
  17.  
    Private m_ForeGradientMode As LinearGradientMode = LinearGradientMode.Vertical
  18.  
    Private m_ForeGradient As Boolean = False
  19.  
    Private m_OffsetY As Integer = 0
  20.  
    Private m_OutlineColor As Color = Color.White
  21.  
    Private m_OutlineWidth As Integer = 0
  22.  
     
  23.  
    'This property get/set text outline border color
  24.  
    Public Property OutlineColor() As Color
  25.  
    Get
  26.  
    Return m_OutlineColor
  27.  
    End Get
  28.  
    Set(ByVal value As Color)
  29.  
    m_OutlineColor = value
  30.  
    Me.Invalidate()
  31.  
    End Set
  32.  
    End Property
  33.  
     
  34.  
    'This property get/set text outline border width
  35.  
    'If set to zero, then it's not outline
  36.  
    Public Property OutlineWidth() As Integer
  37.  
    Get
  38.  
    Return m_OutlineWidth
  39.  
    End Get
  40.  
    Set(ByVal value As Integer)
  41.  
    m_OutlineWidth = value
  42.  
    Me.Invalidate()
  43.  
    End Set
  44.  
    End Property
  45.  
     
  46.  
    'This property get/set an integer value that represents
  47.  
    'the number of pixels that must close up the normal text and
  48.  
    'the reflected text. As MeasureString considers special characters
  49.  
    'and glyphos, it returns vertically an extra space. The OffsetY
  50.  
    'property tells the control to dispose N pixels of space between
  51.  
    'the drawn texts.
  52.  
    Public Property OffsetY() As Integer
  53.  
    Get
  54.  
    Return m_OffsetY
  55.  
    End Get
  56.  
    Set(ByVal value As Integer)
  57.  
    m_OffsetY = value
  58.  
    Me.Invalidate()
  59.  
    End Set
  60.  
    End Property
  61.  
     
  62.  
    'This property get/set a value indicating if draw the texts
  63.  
    'using a gradient fill (true) or a solid fill (false)
  64.  
    Public Property ForeGradient() As Boolean
  65.  
    Get
  66.  
    Return m_ForeGradient
  67.  
    End Get
  68.  
    Set(ByVal value As Boolean)
  69.  
    m_ForeGradient = value
  70.  
    Me.Invalidate()
  71.  
    End Set
  72.  
    End Property
  73.  
     
  74.  
    'This property get/set a value indicating the direction of
  75.  
    'the texts gradient fill
  76.  
    Public Property ForeGradientMode() As LinearGradientMode
  77.  
    Get
  78.  
    Return m_ForeGradientMode
  79.  
    End Get
  80.  
    Set(ByVal value As LinearGradientMode)
  81.  
    m_ForeGradientMode = value
  82.  
    Me.Invalidate()
  83.  
    End Set
  84.  
    End Property
  85.  
     
  86.  
    'This property get/set a value indicating the second color of
  87.  
    'the texts gradient fill
  88.  
    Public Property ForeGradientColor2() As Color
  89.  
    Get
  90.  
    Return m_ForeGradientColor2
  91.  
    End Get
  92.  
    Set(ByVal value As Color)
  93.  
    m_ForeGradientColor2 = value
  94.  
    Me.Invalidate()
  95.  
    End Set
  96.  
    End Property
  97.  
     
  98.  
    'This property get/set a value indicating the first color of
  99.  
    'the texts gradient fill
  100.  
    Public Property ForeGradientColor1() As Color
  101.  
    Get
  102.  
    Return m_ForeGradientColor1
  103.  
    End Get
  104.  
    Set(ByVal value As Color)
  105.  
    m_ForeGradientColor1 = value
  106.  
    Me.Invalidate()
  107.  
    End Set
  108.  
    End Property
  109.  
     
  110.  
    'This property get/set a value that represents the level of
  111.  
    'transparency in the reflected text. Values must be between 0 and 255.
  112.  
    'The lower value, reflected text is more transparent.
  113.  
    'The higher value, more opaque.
  114.  
    Public Property Alpha() As Integer
  115.  
    Get
  116.  
    Return m_Alpha
  117.  
    End Get
  118.  
    Set(ByVal value As Integer)
  119.  
    m_Alpha = value
  120.  
    Me.Invalidate()
  121.  
    End Set
  122.  
    End Property
  123.  
     
  124.  
    'This property get/set a value indicating if draw the control's background
  125.  
    'using a gradient fill (true) or a solid fill (false)
  126.  
    Public Property BackGradient() As Boolean
  127.  
    Get
  128.  
    Return m_BackGradient
  129.  
    End Get
  130.  
    Set(ByVal value As Boolean)
  131.  
    m_BackGradient = value
  132.  
    Me.Invalidate()
  133.  
    End Set
  134.  
    End Property
  135.  
     
  136.  
    'This property get/set a value indicating the direction of
  137.  
    'the control's background gradient fill
  138.  
    Public Property BackGradientMode() As LinearGradientMode
  139.  
    Get
  140.  
    Return m_BackGradientMode
  141.  
    End Get
  142.  
    Set(ByVal value As LinearGradientMode)
  143.  
    m_BackGradientMode = value
  144.  
    Me.Invalidate()
  145.  
    End Set
  146.  
    End Property
  147.  
     
  148.  
    'This property get/set a value indicating the second color of
  149.  
    'the control's background gradient fill
  150.  
    Public Property BackGradientColor2() As Color
  151.  
    Get
  152.  
    Return m_BackGradientColor2
  153.  
    End Get
  154.  
    Set(ByVal value As Color)
  155.  
    m_BackGradientColor2 = value
  156.  
    Me.Invalidate()
  157.  
    End Set
  158.  
    End Property
  159.  
     
  160.  
    'This property get/set a value indicating the first color of
  161.  
    'the control's background gradient fill
  162.  
    Public Property BackGradientColor1() As Color
  163.  
    Get
  164.  
    Return m_BackGradientColor1
  165.  
    End Get
  166.  
    Set(ByVal value As Color)
  167.  
    m_BackGradientColor1 = value
  168.  
    Me.Invalidate()
  169.  
    End Set
  170.  
    End Property
  171.  
     
  172.  
    'The AutoSize property has been overridden to achieve the control
  173.  
    'not to be auto-sized.
  174.  
    Public Overrides Property AutoSize() As Boolean
  175.  
    Get
  176.  
    Return MyBase.AutoSize
  177.  
    End Get
  178.  
    Set(ByVal value As Boolean)
  179.  
    MyBase.AutoSize = False
  180.  
    End Set
  181.  
    End Property
  182.  
     
  183.  
    'The TextAlign property has been overridden to achieve the control text
  184.  
    'be aligned always at Middle-Center.
  185.  
    Public Overrides Property TextAlign() As System.Drawing.ContentAlignment
  186.  
    Get
  187.  
    Return MyBase.TextAlign
  188.  
    End Get
  189.  
    Set(ByVal value As System.Drawing.ContentAlignment)
  190.  
    MyBase.TextAlign = ContentAlignment.MiddleCenter
  191.  
    End Set
  192.  
    End Property
  193.  
     
  194.  
    'All the paintint work is done here.
  195.  
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
  196.  
    With e.Graphics
  197.  
    '*** Apply high-quality properties to the graphics object ************************
  198.  
    .CompositingQuality = CompositingQuality.HighQuality
  199.  
    .InterpolationMode = InterpolationMode.HighQualityBicubic
  200.  
    .PixelOffsetMode = PixelOffsetMode.HighQuality
  201.  
    .SmoothingMode = SmoothingMode.HighQuality
  202.  
    .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
  203.  
     
  204.  
    '*** Draw the control's background ***********************************************
  205.  
    If Me.BackGradient Then
  206.  
    'The background must show a gradient, so we need to create a gradient brush
  207.  
    'and fill the control's background rectangle with this gradient
  208.  
    Using bkg As LinearGradientBrush = New LinearGradientBrush(e.ClipRectangle, Me.BackGradientColor1, Me.BackGradientColor2, Me.BackGradientMode)
  209.  
    .FillRectangle(bkg, e.ClipRectangle)
  210.  
    End Using
  211.  
    Else
  212.  
    'The background is a solid color. The Clear method of the Graphics object
  213.  
    'let us to choose a color to clear the background.
  214.  
    .Clear(Me.BackColor)
  215.  
    End If
  216.  
    '*********************************************************************************
  217.  
     
  218.  
    '*** Create and draw the normal (not reflected) text *****************************
  219.  
    'Get the text width & height
  220.  
    Dim width As Single = .MeasureString(Me.Text, Me.Font).Width
  221.  
    Dim height As Single = .MeasureString(Me.Text, Me.Font).Height
  222.  
     
  223.  
    'Create a rectangle that delimites the position & size of the text drawn
  224.  
     
  225.  
    'The x position must be (control width - text width) / 2, so the text will be
  226.  
    'horizontally centered
  227.  
    Dim xpos As Single = (e.ClipRectangle.Width - width) / 2
  228.  
     
  229.  
    'The y position must be also vertically centered, so we start from
  230.  
    '(control height - text height) / 2
  231.  
    'But below the normal text will be the reflected text, so must offset to top
  232.  
    'the half of text height
  233.  
    'Additionally, MeasureString give us extra space reserved for tall glyphos,
  234.  
    'so must consider the OffsetY value to delete this extra space, so must offset
  235.  
    'to bottom the half of OffsetY value
  236.  
    Dim ypos As Single = ((e.ClipRectangle.Height - height) / 2) - (height / 2) + (Me.OffsetY / 2)
  237.  
     
  238.  
    'Finally, create the rectangle from x,y pos and width & height of the text
  239.  
    Dim originalRect As New RectangleF(xpos, ypos, width, height)
  240.  
     
  241.  
    'Draw the original string. We'll use a GraphicsPath object instead
  242.  
    'using DrawString directly, because GraphicsPath will let us draw an
  243.  
    'outline border to the text
  244.  
     
  245.  
    'Create the path
  246.  
    Dim path As GraphicsPath = New GraphicsPath
  247.  
     
  248.  
    'Add the string to the path. Because GraphicsPath's AddString method
  249.  
    'uses emSize (the height of the em square box that bounds the character)
  250.  
    'instead of Point, we must convert out font's Point size to emSize using
  251.  
    'this formula: (Vertical Resolution / 72) * Font's Point Size
  252.  
    path.AddString(Me.Text, Me.Font.FontFamily, Me.Font.Style, (.DpiY / 72) * Me.Font.Size, originalRect, StringFormat.GenericDefault)
  253.  
     
  254.  
    'If and outline must be drawn, draw it
  255.  
    If Me.OutlineWidth > 0 Then
  256.  
    Using p As Pen = New Pen(Me.OutlineColor, Me.OutlineWidth)
  257.  
    .DrawPath(p, path)
  258.  
    End Using
  259.  
    End If
  260.  
     
  261.  
    'Create the brush to fill the text
  262.  
    Dim fill As Brush
  263.  
    If Me.ForeGradient Then
  264.  
    'Text must be filled with a gradient brush
  265.  
    fill = New LinearGradientBrush(originalRect, Me.ForeGradientColor1, Me.ForeGradientColor2, Me.ForeGradientMode)
  266.  
    Else
  267.  
    'Text must be filled with a solid brush
  268.  
    fill = New SolidBrush(Me.ForeColor)
  269.  
    End If
  270.  
     
  271.  
    'Fill the text and destroy the brush
  272.  
    .FillPath(fill, path)
  273.  
    fill.Dispose()
  274.  
     
  275.  
    'The GraphicsPath object won't be needed anymore
  276.  
    path.Dispose()
  277.  
     
  278.  
    'From this point we must deal with reflected text. So it's a good idea to
  279.  
    'save the current state of our graphics object. What is really saved is the
  280.  
    'state of the objects (transformations applied, etc), not the drawings done
  281.  
    'until here.
  282.  
    Dim state As GraphicsState = .Save
  283.  
     
  284.  
    'Reset the transformations done until here so we start from a "fresh clean"
  285.  
    'graphics object state.
  286.  
    .ResetTransform()
  287.  
     
  288.  
    'ScaleTransform will set the graphics object into a state in which all the
  289.  
    'drawings done after the instruction will be affected by the scaling done.
  290.  
    'As we use 1 for horizontal value, the drawings will be not changed in the
  291.  
    'horizontal plane. But as we use -1 for the vertical value, all the drawings
  292.  
    'will be vertically inverted (the reflection effect that we want).
  293.  
    .ScaleTransform(1, -1)
  294.  
     
  295.  
    'Now, as we did for the normal text, we'll create a rectangle that delimites
  296.  
    'the position and size of the reflected text
  297.  
     
  298.  
    'The x-position must not be changed, as it is the same (horizontally centered)
  299.  
     
  300.  
    'The y-pos must be vertically centered, so we start from
  301.  
    '(control height - text height) / 2
  302.  
    'From there, as we did with normal text, we must offset the half of the text height
  303.  
    '(in this case, offset to top)
  304.  
    'Also must offset the OffsetY value, to top too
  305.  
    'BUT we must remember that this will be drawn over a transformed (Scaled)
  306.  
    'graphics object, so must invert all signs (for example, offset to bottom instead
  307.  
    'to top)
  308.  
    ypos = (((((e.ClipRectangle.Height - height) / 2) + (height / 2)) * -1) - height) + (Me.OffsetY / 2)
  309.  
     
  310.  
    'Create the rectangle
  311.  
    Dim reflectedRect As New RectangleF(xpos, ypos, width, height)
  312.  
     
  313.  
    'Create the path to hold the text
  314.  
    Dim reflectedPath As GraphicsPath = New GraphicsPath
  315.  
     
  316.  
    'Add the string to the path
  317.  
    reflectedPath.AddString(Me.Text, Me.Font.FontFamily, Me.Font.Style, (.DpiY / 72) * Me.Font.Size, reflectedRect, StringFormat.GenericDefault)
  318.  
     
  319.  
    'Draw the outline, if it applies
  320.  
    If Me.OutlineWidth > 0 Then
  321.  
    'Note that we apply alpha transparency to the outline. If not, reflected
  322.  
    'text's outline will appear too much "solid"
  323.  
    Using p As Pen = New Pen(Color.FromArgb(Me.Alpha, Me.OutlineColor), Me.OutlineWidth)
  324.  
    .DrawPath(p, reflectedPath)
  325.  
    End Using
  326.  
    End If
  327.  
     
  328.  
    'Create the brush to fill the reflected text
  329.  
    If Me.ForeGradient Then
  330.  
    'We must apply Alpha transparency on both gradient colors
  331.  
    fill = New LinearGradientBrush(reflectedRect, Color.FromArgb(Me.Alpha, Me.ForeGradientColor1), Color.FromArgb(Me.Alpha, Me.ForeGradientColor2), Me.ForeGradientMode)
  332.  
    Else
  333.  
    'Apply Alpha to solid color too
  334.  
    fill = New SolidBrush(Color.FromArgb(Me.Alpha, Me.ForeColor))
  335.  
    End If
  336.  
     
  337.  
    'Draw the text (it will be automatically reflected because of the Scale
  338.  
    'transformation applied)
  339.  
    .FillPath(fill, reflectedPath)
  340.  
     
  341.  
    'Destroy objects that are no more needed
  342.  
    fill.Dispose()
  343.  
    reflectedPath.Dispose()
  344.  
     
  345.  
    'Restore the Graphics object state (eliminate transformations, so if we drew
  346.  
    'anymore from here will not be reflected)
  347.  
    .Restore(state)
  348.  
    '*********************************************************************************
  349.  
    End With
  350.  
    End Sub
  351.  
    End Class
 

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


相关教程