Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

My Fake Button Part 1

0.00/5 (No votes)
27 Jan 2012 1  
How to make a fake button using GDI+.

Introduction

Hi all,

Before you begin, first I wish to apologize profusely. This happens because my English is very bad, that's why I wrote this article using google translator. Once again I say apologize profusely.

This is my first time writing an article. So, when things go wrong, please be informed where lies the fault.

I have long been studying and using Visual Basic, starting from version 5. And on this occasion, I would like to share about GDI +. For me, when I know GDI +. I am really amazed he made. Known, this occurs because the Visual Basic 5 and Visual Basic 6 does not know him. And a still more remarkable is, you can test the accuracy of the mouse cursor when you click on an area. If you have MSDN, you can learn it by opening a page How to: Use Hit Testing with a Region. After reading the article, it suddenly occurred to me, and my heart said, wait a second, this is basically making a control.

Let's begin

After run Visual Basic. Make a project of type Windows Application. And after that name them GDIPP01. GDIPP01 is an extension of GDI + Project 1. Only an acronym's after all. Once the project is made, then you will find the file Form1.vb. At this time you do not need to change its name. After that create a new file with type of Code File, and you do not need to change its name. So by default the file will be named CodeFile1.vb.

Before starting, I will explain in outline what will be done later, starting from:

  • MyPath.

MyPath is a module. This module serves to manipulate the path and the region.

  • MyColor.

MyColor is a module of type component classes. This component will be used to manipulate color. Where the outcome can be either Color or Brush.

  • MyButton.

MyButton is a class module that component type. This component which will make a fake button on the Form1.vb

Notes: MyPath, MyColor and MyButton will be created in one class only, which is CodeFile1.vb.

And now, go into code view window owned CodeFile1.vb file. And after that type the following code:

Imports System.ComponentModel

Public Module MyPath
    Dim vPath As New Drawing2D.GraphicsPath
    Function GetRoundedRectangle(ByVal Size As SizeF, ByVal Rounded As Single) As Drawing2D.GraphicsPath
        vPath.Dispose()
        vPath = New Drawing2D.GraphicsPath

        Dim r1 As New Rectangle(0, 0, Rounded * 2, Rounded * 2)
        Dim r2 As New Rectangle(Size.Width - r1.Width, 0, r1.Width, r1.Height)
        Dim r3 As New Rectangle(r2.X, Size.Height - r1.Height, r1.Width, r1.Height)
        Dim r4 As New Rectangle(r1.X, r3.Y, r1.Width, r1.Height)

        Dim l1() As PointF = {New PointF(Rounded, 0), New PointF(Size.Width - Rounded, 0)}
        Dim l2() As PointF = {New PointF(Size.Width, Rounded), New PointF(Size.Width, Size.Height - Rounded)}
        Dim l3() As PointF = {New PointF(Size.Width - Rounded, Size.Height), New PointF(Rounded, Size.Height)}
        Dim l4() As PointF = {New PointF(0, Size.Height - Rounded), New PointF(0, Rounded)}

        vPath.AddArc(r1, -180, 90)
        vPath.AddLines(l1)
        vPath.AddArc(r2, -90, 90)
        vPath.AddLines(l2)
        vPath.AddArc(r3, 0, 90)
        vPath.AddLines(l3)
        vPath.AddArc(r4, 90, 90)
        vPath.AddLines(l4)

        Return vPath
    End Function
End Module

Up here, You have finished making MyPath Module. And now we will make MyColor Class. Here's what you should type:

Public Class MyColor
    Inherits Component

    Dim vColor As Color = Drawing.Color.White
    Dim vTransBool As Boolean = False
    Dim vTransInt As Integer = 255
    Event ColorChanged(ByVal o As Object)
    Property Color() As Color
        Get
            Return vColor
        End Get
        Set(ByVal value As Color)
            vColor = value
            RaiseEvent ColorChanged(Me)
        End Set
    End Property
    Property CanTransparent() As Boolean
        Get
            Return vTransBool
        End Get
        Set(ByVal value As Boolean)
            vTransBool = value
            RaiseEvent ColorChanged(Me)
        End Set
    End Property
    Property TransparentValue() As Integer
        Get
            Return vTransInt
        End Get
        Set(ByVal value As Integer)
            vTransInt = value
            RaiseEvent ColorChanged(Me)
        End Set
    End Property
    Function GetColor() As Color
        With Me
            If .vTransBool = True Then
                Return Drawing.Color.FromArgb(.vTransInt, .vColor)
            Else
                Return .vColor
            End If
        End With
    End Function
    Function GetBrush() As Brush
        Return New SolidBrush(Me.GetColor)
    End Function

    Sub New()
        MyBase.New()
    End Sub
    Sub New(ByVal Color As Color, Optional ByVal CanTransparent As Boolean = False, Optional ByVal TransparentValue As Integer = 255)
        MyBase.New()
        With Me
            .Color = Color
            .CanTransparent = CanTransparent
            .TransparentValue = TransparentValue
        End With
    End Sub
End Class

Up here yo have finished making MyColor Class. Next we will make MyButton Class. Here's what you should type:

Public Class MyButton
    Inherits Component

#Region "- Building Layout -"
    Dim vRect As New RectangleF(0, 0, 100, 30)
    Private Const CLayout As String = "Layout"
    <Category(CLayout)> _
    Property LayoutLeft() As Single
        Get
            Return vRect.X
        End Get
        Set(ByVal value As Single)
            vRect.X = value
        End Set
    End Property
    <Category(CLayout)> _
    Property LayoutTop() As Single
        Get
            Return vRect.Y
        End Get
        Set(ByVal value As Single)
            vRect.Y = value
        End Set
    End Property
    <Category(CLayout)> _
    Property LayoutWidth() As Single
        Get
            Return vRect.Width
        End Get
        Set(ByVal value As Single)
            vRect.Width = value
        End Set
    End Property
    <Category(CLayout)> _
    Property LayoutHeight() As Single
        Get
            Return vRect.Height
        End Get
        Set(ByVal value As Single)
            vRect.Height = value
        End Set
    End Property
    Function GetRectangle() As Rectangle
        Return New Rectangle(vRect.X, vRect.Y, vRect.Width, vRect.Height)
    End Function
    Function GetRectangleF() As RectangleF
        Return vRect
    End Function
#End Region

#Region "- Matrix -"
    Dim vScale As New PointF(1, 1)
    Dim vShear As New PointF
    Dim vRotate As Single
    Private Const CMatrix As String = "Matrix"
    <Category(CMatrix)> _
    Property MatrixRotate() As Single
        Get
            Return vRotate
        End Get
        Set(ByVal value As Single)
            vRotate = value
        End Set
    End Property
    <Category(CMatrix)> _
    Property MatrixScaleX() As Single
        Get
            Return vScale.X
        End Get
        Set(ByVal value As Single)
            vScale.X = value
        End Set
    End Property
    <Category(CMatrix)> _
    Property MatrixScaleY() As Single
        Get
            Return vScale.Y
        End Get
        Set(ByVal value As Single)
            vScale.Y = value
        End Set
    End Property
    <Category(CMatrix)> _
    Property MatrixShearX() As Single
        Get
            Return vShear.X
        End Get
        Set(ByVal value As Single)
            vShear.X = value
        End Set
    End Property
    <Category(CMatrix)> _
    Property MatrixShearY() As Single
        Get
            Return vShear.Y
        End Get
        Set(ByVal value As Single)
            vShear.Y = value
        End Set
    End Property
#End Region

#Region "- Font & String Format -"
    Dim vFont As New Font("tahoma", 8)
    Dim vFormat As New StringFormat
    Dim vStr As String = "My Button"
    Dim WithEvents vStrColor As New MyColor(Color.Yellow)
    Private Const CFont As String = "Writing Styles"
    <Category(CFont)> _
    Property StringFont() As Font
        Get
            Return vFont
        End Get
        Set(ByVal value As Font)
            vFont = value
        End Set
    End Property
    <Category(CFont)> _
    Property StringVerticalAlingment() As StringAlignment
        Get
            Return vFormat.Alignment
        End Get
        Set(ByVal value As StringAlignment)
            vFormat.Alignment = value
        End Set
    End Property
    <Category(CFont)> _
    Property StringHorizontalAlingment() As StringAlignment
        Get
            Return vFormat.LineAlignment
        End Get
        Set(ByVal value As StringAlignment)
            vFormat.LineAlignment = value
        End Set
    End Property
    <Category(CFont)> _
    Property StringTrimming() As StringTrimming
        Get
            Return vFormat.Trimming
        End Get
        Set(ByVal value As StringTrimming)
            vFormat.Trimming = value
        End Set
    End Property
    <Category(CFont)> _
    Property StringFormatFlags() As StringFormatFlags
        Get
            Return vFormat.FormatFlags
        End Get
        Set(ByVal value As StringFormatFlags)
            vFormat.FormatFlags = value
        End Set
    End Property
    <Category(CFont)> _
    Property StringText() As String
        Get
            Return vStr
        End Get
        Set(ByVal value As String)
            vStr = value
        End Set
    End Property
    <Category(CFont)> _
    ReadOnly Property StringColor() As MyColor
        Get
            Return vStrColor
        End Get
    End Property
#End Region

#Region "- Gradient -"
    Dim WithEvents vColor1 As New MyColor(Color.Red), vColor2 As New MyColor(Color.Blue)
    Dim vColorRotate As Single
    Dim vGamma As Boolean = False
    Private Const CBackcolor As String = "Background Color"
    <Category(CBackcolor)> _
    ReadOnly Property GradientColor1() As MyColor
        Get
            Return vColor1
        End Get
    End Property
    <Category(CBackcolor)> _
    ReadOnly Property GradientColor2() As MyColor
        Get
            Return vColor2
        End Get
    End Property
    <Category(CBackcolor)> _
    Property GradientRotate() As Single
        Get
            Return vColorRotate
        End Get
        Set(ByVal value As Single)
            vColorRotate = value
        End Set
    End Property
    <Category(CBackcolor)> _
    Property GradientGamma() As Boolean
        Get
            Return vGamma
        End Get
        Set(ByVal value As Boolean)
            vGamma = value
        End Set
    End Property
#End Region

#Region "- Else -"
    Dim vRounded As Single = 10
    Private Const CElse As String = "Else"
    <Category(CElse)> _
    Property Rounded() As Single
        Get
            Return vRounded
        End Get
        Set(ByVal value As Single)
            vRounded = value
        End Set
    End Property
#End Region

    Dim vMousePress, vMouseFocus As Boolean
    Dim vMousePoint As New Point
    Private Function OnAreaTarget(ByVal p As Point) As Boolean
        With Me
            Try
                Using m1 As New Drawing2D.Matrix
                    m1.RotateAt(.vRotate, New PointF(.vRect.Width / 2, .vRect.Height / 2))
                    m1.Scale(.vScale.X, .vScale.Y)
                    m1.Shear(.vShear.X, .vShear.Y)
                    Using m2 As New Drawing2D.Matrix
                        m2.Translate(.vRect.X, .vRect.Y)
                        m2.Multiply(m1)
                        Using gp As New Drawing2D.GraphicsPath
                            gp.AddPath(MyPath.GetRoundedRectangle(.vRect.Size, .vRounded), False)
                            gp.Transform(m2)
                            Using Region As New Region(gp)
                                Return Region.IsVisible(p)
                            End Using
                        End Using
                    End Using
                End Using
            Catch ex As Exception
            End Try
        End With
    End Function

    Dim WithEvents vControl As New Control
    Event Click(ByVal o As Object)
    Event DoubleClick(ByVal o As Object)
    Sub BindingControl(ByVal c As Control)
        vControl = c
    End Sub
    Private Sub eColorChanged(ByVal o As Object) Handles vColor1.ColorChanged, vColor2.ColorChanged, vStrColor.ColorChanged
        Me.vControl.Invalidate()
    End Sub
    Private Sub ePaint(ByVal o As Object, ByVal e As PaintEventArgs) Handles vControl.Paint
        With Me
            Try
                Dim g As Graphics = e.Graphics

                Dim gc As Drawing2D.GraphicsContainer = g.BeginContainer

                g.CompositingQuality = Drawing2D.CompositingQuality.AssumeLinear
                g.PixelOffsetMode = Drawing2D.PixelOffsetMode.Half
                g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
                g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias

                Dim Path As New Drawing2D.GraphicsPath
                Path.AddPath(MyPath.GetRoundedRectangle(.vRect.Size, .vRounded), False)

                Using m1 As New Drawing2D.Matrix
                    m1.RotateAt(.vRotate, New PointF(.vRect.Width / 2, .vRect.Height / 2))
                    m1.Scale(.vScale.X, .vScale.Y)
                    m1.Shear(.vShear.X, .vShear.Y)
                    Using m2 As New Drawing2D.Matrix
                        m2.Translate(.vRect.X, .vRect.Y)
                        m2.Multiply(m1)
                        g.MultiplyTransform(m2)
                    End Using
                End Using

                Using lgb As New Drawing2D.LinearGradientBrush(New Rectangle(0, 0, .vRect.Width, .vRect.Height), .vColor1.GetColor, .vColor2.GetColor, .vColorRotate, True)
                    lgb.GammaCorrection = .vGamma
                    g.FillPath(lgb, Path)
                End Using

                If .vMouseFocus = True Then
                    Using Trans As New MyColor(Color.White, True, 50)
                        g.FillRectangle(Trans.GetBrush, New Rectangle(0, 0, .vRect.Width, IIf(.vMousePress, .vRect.Height / 2, .vRect.Height / 2.4)))
                    End Using
                End If

                g.DrawString(.vStr, .vFont, .vStrColor.GetBrush, New Rectangle(4, 4, .vRect.Width - 8, .vRect.Height - 8), .vFormat)

                If .vMouseFocus = True Then
                    g.DrawPath(New Pen(Color.Orange, IIf(.vMousePress, 4, 2)), Path)
                End If

                Path.Dispose()

                g.EndContainer(gc)
            Catch ex As Exception
            End Try
        End With
    End Sub
    Private Sub eMouseClick(ByVal o As Object, ByVal e As MouseEventArgs) Handles vControl.MouseClick
        If Me.OnAreaTarget(e.Location) = True Then
            RaiseEvent Click(Me)
        End If
    End Sub
    Private Sub eMouseDoubleClick(ByVal o As Object, ByVal e As MouseEventArgs) Handles vControl.MouseDoubleClick
        If Me.OnAreaTarget(e.Location) = True Then
            RaiseEvent DoubleClick(Me)
        End If
    End Sub
    Private Sub eMouseDown(ByVal o As Object, ByVal e As MouseEventArgs) Handles vControl.MouseDown
        With Me
            Try
                If .OnAreaTarget(e.Location) = True Then
                    If .vMousePress = False Then
                        .vMousePress = True
                        .vControl.Invalidate()
                    Else
                        .vMousePress = True
                    End If
                End If
            Catch ex As Exception
            End Try
        End With
    End Sub
    Private Sub eMouseUp(ByVal o As Object, ByVal e As MouseEventArgs) Handles vControl.MouseUp
        With Me
            Try
                If .vMousePress = True Then
                    .vMousePress = False
                    .vControl.Invalidate()
                Else
                    .vMousePress = False
                End If
            Catch ex As Exception
            End Try
        End With
    End Sub
    Private Sub eMouseMove(ByVal o As Object, ByVal e As MouseEventArgs) Handles vControl.MouseMove
        With Me
            Try
                If .OnAreaTarget(e.Location) = True Then
                    If .vMouseFocus = False Then
                        .vMouseFocus = True
                        .vControl.Invalidate()
                    Else
                        .vMouseFocus = True
                    End If
                Else
                    If .vMouseFocus = True Then
                        .vMouseFocus = False
                        .vControl.Invalidate()
                    Else
                        .vMouseFocus = False
                    End If
                End If
            Catch ex As Exception
            End Try
        End With
    End Sub

    Sub New()
        MyBase.New()
        With Me
            Try
                With .vFormat
                    .Alignment = StringAlignment.Center
                    .LineAlignment = StringAlignment.Center
                    .FormatFlags = Drawing.StringFormatFlags.DisplayFormatControl
                    .Trimming = Drawing.StringTrimming.EllipsisCharacter
                End With
            Catch ex As Exception
            End Try
        End With
    End Sub
End Class

Up here yo have finished making MyButton Class. Immediately you build your project. Later, if successful you will find two new components in the toolbox window, illustrated more or less like the following:

After that, you drag a window MyButton component to design view owned Form1.vb. After that, this is what happened:

At this time, MyButton component has been created. And now look at the properties window. This is all property owned by MyButton:

And now, let's remove the existing MyButton1 components in Form1.vb. This is done because I prefer to design a code via the code window than the design view window. After that, let's go into the code window owned by Form1.vb, and type the following code:

Public Class Form1
    Dim WithEvents vComboBox As New ComboBox
    Dim WithEvents vButtonMin, vButtonMax, vButtonNormal, vButtonOut As New MyButton
    Dim WithEvents vPropGrid As New PropertyGrid
    Private Sub eLoad(ByVal o As System.Object, ByVal e As EventArgs) Handles MyBase.Load
        With Me
            Try
                .DoubleBuffered = True
                .ControlBox = False

                Dim ArrayString() As String = {"Minimum", "Maximum", "Normal", "Close"}
                .vComboBox.Items.AddRange(ArrayString)
                .vComboBox.DropDownStyle = ComboBoxStyle.DropDownList
                .vComboBox.Width = 200
                .vComboBox.SelectedIndex = 0

                Dim ArrayButton() As MyButton = {.vButtonMin, .vButtonMax, .vButtonNormal, .vButtonOut}
                For a As Integer = 0 To ArrayButton.Length - 1
                    ArrayButton(a).LayoutLeft = 10
                    If a = 0 Then
                        ArrayButton(a).LayoutTop = 10
                    Else
                        ArrayButton(a).LayoutTop = ArrayButton(a - 1).LayoutTop + ArrayButton(a - 1).LayoutHeight + 10
                    End If
                    ArrayButton(a).StringText = ArrayString(a)
                    ArrayButton(a).BindingControl(Me)
                Next

                .Controls.Add(.vComboBox)
                .Controls.Add(.vPropGrid)

                .Size = New Size(640, 480)
            Catch ex As Exception
            End Try
        End With
    End Sub
    Private Sub eResize(ByVal o As Object, ByVal e As EventArgs) Handles Me.Resize
        With Me
            Try
                .vComboBox.Location = New Point(.ClientSize.Width - .vComboBox.Width - 10, 10)

                .vPropGrid.Location = New Point(.vComboBox.Left, .vComboBox.Bottom + 10)
                .vPropGrid.Size = New Size(.vComboBox.Width, .ClientSize.Height - .vPropGrid.Top - 10)

                .Invalidate()
            Catch ex As Exception
            End Try
        End With
    End Sub
    Private Sub eComboBoxSelIndexChanged(ByVal o As Object, ByVal e As EventArgs) Handles vComboBox.SelectedIndexChanged
        With Me
            Try
                Dim ArrayButton() As MyButton = {.vButtonMin, .vButtonMax, .vButtonNormal, .vButtonOut}
                .vPropGrid.SelectedObject = ArrayButton(.vComboBox.SelectedIndex)
            Catch ex As Exception
            End Try
        End With
    End Sub
    Private Sub ePropValChanged(ByVal s As Object, ByVal e As PropertyValueChangedEventArgs) Handles vPropGrid.PropertyValueChanged
        Me.Invalidate()
    End Sub
    Private Sub eMyButtonClick(ByVal o As Object) Handles vButtonMin.Click, vButtonMax.Click, vButtonNormal.Click, vButtonOut.Click
        With Me
            Try
                If o Is .vButtonMin Then
                    .WindowState = FormWindowState.Minimized
                End If

                If o Is .vButtonMax Then
                    .WindowState = FormWindowState.Maximized
                End If

                If o Is .vButtonNormal Then
                    .WindowState = FormWindowState.Normal
                End If

                If o Is .vButtonOut Then
                    .Close()
                End If
            Catch ex As Exception
            End Try
        End With
    End Sub
End Class

When finished typing the code listed above, we just run the program. Later, more or less looks like the following:

And now, you can test all the buttons. And also you can change the value of property owned by each of the buttons. To do so, you just need to click the combobox which available, more or less like this illustration:

After that click on the items available. For example, I change some property values owned by vButtonNormal as follows:

Property

Value

Rounded

30

LayoutHeight

100

LayoutLeft

120

MatrixRotate

10

MatrixShearY

0.5

StringFont -> Size

12

And the results are more or less like the following:

Points of Interest

Interesting is not it. When the control is normally not able to do things like that. Precisely control which fake, in this case MyButton, could do such a thing. Until this is my first article this time. If anyone wants to ask, you can send an email to wahyu.pratama@hotmail.com.

History

Keep a running update of any changes or improvements you've made here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here