Introduction
I consider myself a newbie in VB.NET programming since I only have 3 months of hands-on experience with VB.NET. While working on a project at my new job, I noticed that Visual studio .NET provides developers with only one button which is the rectangular button. I was curious to create another shape for a button. I asked myself how hard it is to create a button control. I thought it would be really hard to create one, especially with a 3D effect. So, I decided to hit the books and start reading about GDI programming and how to build controls for .NET using VB.NET. I printed a form with a few regular buttons on it and I started staring at them. I noticed if I had the form upside down, the buttons would look as if they were pushed. I then noticed that the top line and the left line of the button had a lighter colour while the bottom line and right line are drawn in black or a dark colour. I said to myself that it might be much easier than I thought to draw the button.
The elliptical control has two styles: Standard
, which has the 3D affect, and Popup
, which looks flat unless the mouse cursor goes on top of it which makes it look like the Standard
style.
I might have little experience in programming compared to many writers in this website. But I am really pleased to share my new knowledge with everyone and I will be really happy if I get any feedback from you.
Variables and Properties
mousePressed
- Boolean
- True
if the button is pressed. False
otherwise.
MeGotFocus
- Boolean
- True
if the button is has focus. False
otherwise.
MouseOver
- Boolean
- True
if the cursor is over the button. False
otherwise.
ButtonStyle
- Standard
or Popup
.
ButtonImage
- Button
- bitmap image.
Image
- Gets or sets the button bitmap image.
Text
- Gets or sets the text associated with this control.
FlatStyle
- Gets or sets the flat style appearance of the Button
control.
Painting the Button
I started building the button by inheriting from the class Control
. Inheriting from Class control provided me with all the events I needed such as onClick
, onMouseUp
, onMouseDown
, onKeyUp
, onKeyDown
, and most importantly, the onPaint
method.
When I started writing the onPaint
event, I was using only the Graphics
class which is wrong. Before starting to draw the lines of the button, we need to draw the Region
of the button by using the GraphicsPath
class.
Dim a As New System.Drawing.Drawing2D.GraphicsPath
recRegion = New RectangleF(0, 0, Me.Width, Me.Height)
a.AddEllipse(recRegion)
Me.Region = New Region(a)
After drawing the elliptical region, it is time to draw the lines. I used the DrawArc
method to draw the edges of the button. I chose the controlDarkDark
colour to draw the bottom arc and the controlLightLight
colour to draw the upper arc when the button is not pressed. Before drawing using the Graphics
class, it is really recommended to set the SmoothingMode
property to AntiAlias
. Otherwise, the drawn lines will not be smooth and the button will look really ugly.
Dim p1 As Pen
Dim p2 As Pen
recBorder = New RectangleF(1, 1, Me.Width - 2, Me.Height - 2)
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
g.DrawArc(p1, recBorder, 180, -180)
g.DrawArc(p2, recBorder, 180, 180)
Now we have a blank elliptical button with no text or image. For this example, I chose to have the text centered in the button if an image does not exist. However, if the user populated the Image
property, the text is left justified.
The following code checks if the mouse is pressed or not and if the Image
property is populated. The g.MeasureString
is really helpful. It returns the drawn size of the text, which is used to calculate the starting point for the drawn text. To simulate the 3D effect when the button is pushed, the text and the image (if applicable) are shifted two pixels to the right and two pixels to the bottom.
Dim textSize As SizeF = g.MeasureString(Me.Text, Me.Font)
If Me.mousePressed Then
If Me._Image Is Nothing Then
g.DrawString(Me.Text, Me.Font, stringBrush, _
(((Me.Width + 3) - textSize.Width) / 2) + 2, _
(((Me.Height + 2) - textSize.Height) / 2) + 2)
Else
Dim pt As New Point(((Me.Width + 3) / 12) + 1, _
((Me.Height + 2 - 16) / 2) + 1)
Dim recString As New Rectangle(pt, New Size(16, 16))
g.DrawImage(_Image, recString)
g.DrawString(Me.Text, Me.Font, stringBrush, _
recString.X + recString.Width + 3,
(((Me.Height + 2) - textSize.Height) / 2) + 2)
End If
Else
If Me._Image Is Nothing Then
g.DrawString(Me.Text, Me.Font, stringBrush, _
(((Me.Width + 3) - textSize.Width) / 2), _
(((Me.Height + 2) - textSize.Height) / 2))
Else
Dim pt As New Point((Me.Width + 3) / 12, (Me.Height + 2 - 16) / 2)
Dim recString As New Rectangle(pt, New Size(16, 16))
g.DrawImage(_Image, recString)
g.DrawString(Me.Text, Me.Font, stringBrush, _
recString.X + recString.Width + 3,
(((Me.Height + 2) - textSize.Height) / 2))
End If
End If
The only difference between the standard style button and the popup style is border colours. The upper arc (from 0 � 180 degrees) for the standard button, as I mentioned before, is drawn with the controlLightLight
colour and the bottom arc (from 0- (-180) degrees) is drawn with the controlDarkDark
colour. The popup style border, however, is drawn using one colour if the mouse cursor is not within the button region.
If Me.MouseOver = True Then
If Me.mousePressed Then
p1 = New Pen(SystemColors.ControlDarkDark, 1)
p2 = New Pen(SystemColors.ControlDarkDark, 1)
Else
p1 = New Pen(SystemColors.ControlDarkDark, 1)
p2 = New Pen(SystemColors.ControlLightLight, 1)
End If
Else
p1 = New Pen(SystemColors.ControlDark, 1.5)
p2 = New Pen(SystemColors.ControlDark, 1.5)
End If
I wanted this button to look as professional as skills allow me. Therefore, I decided to make it to show that it has focus by drawing a dotted ellipse when the button has focus.
If Me.MeGotFocus Then
Dim gotFocusPen As New Pen(Color.Black, 1.3)
Dim recFocus As Rectangle
gotfocuspen.DashStyle = Drawing2D.DashStyle.Dot
gotfocuspen.DashCap = Drawing2D.DashCap.Round
recFocus = New Rectangle(4, 4, Me.Width - 8, Me.Height - 8)
g.DrawEllipse(gotFocusPen, recFocus)
End If
History
This is an initial release for the control. I will be adding the flat style soon as well. So, stay tuned. If you have any suggestions, please let me know.