Introduction
Recently I was searching for a control that would look like the new XP/VS.NET style button control. The button control needed to have the features described in this article. But I couldn't find a free control that provided all these features, so I created one myself. This is my first version, it provides basic functionality that you can already use. But there will soon be more features added.
Feature 1: Basic button functionality
Ah, this is an easy one most people would think. Ofcourse there must be a simple OnClick
event:
Public Shadows Event Click(ByVal sender As Object, ByVal e As EventArgs)
But if you look at the standard functionality of the Button
control provided in the .NET framework, you will see that there are some more things needed for the basic button functionality. The first one is that you can set the Text
property to '&Save', and when you press the keys alt+S, the Click
event of the button would be triggered. I've searched a long time after this one, but with some help in a few newsgroups I managed to add this functionality by overriding the ProcessMnenomic
function:
Protected Overrides Function ProcessMnemonic(ByVal charCode As Char) _
As Boolean
Dim ampPosition As Integer = _text.IndexOf("&")
Dim charToCheck As Char
If ampPosition > -1 And ampPosition < _text.Length Then
charToCheck = _text.Chars(ampPosition + 1)
If Char.ToLower(charToCheck) = Char.ToLower(charCode) Then
Me.PerformClick()
Return True
End If
End If
Return False
End Function
When you place a Button
control on a Form
, you can specify that, that button is the AcceptButton
or CancelButton
. To accomplish this the IButtonControl
interface must be implemented:
<System.ComponentModel.DefaultValue(GetType(DialogResult), Nothing)> _
Public Overridable Overloads Property DialogResult() As DialogResult _
Implements IButtonControl.DialogResult
Get
Return _dialogResult
End Get
Set(ByVal Value As DialogResult)
_dialogResult = Value
End Set
End Property
Public Overridable Overloads Sub NotifyDefault(ByVal value As Boolean) _
Implements IButtonControl.NotifyDefault
End Sub
Public Overridable Overloads Sub PerformClick() Implements _
IButtonControl.PerformClick
SetMouseOver()
clickHandler(Me, Nothing)
SetMouseLeave()
End Sub
This is the basic functionality needed for the button control.
Feature 2: XP style border and backcolor
In Office XP or VS.NET when you move your mouse over a button, the border of the button is painted blue and the backcolor is blue also. This is pretty easy to code:
Private Sub NewFlatButton_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs)_
Handles MyBase.Paint
If Me.blueBorder Then
e.Graphics.DrawRectangle(New Pen(_bordercolorFocus), _
0, 0, Me.Width - 1, Me.Height - 1)
Else
e.Graphics.DrawRectangle(New Pen(_bordercolor), _
0, 0, Me.Width - 1, Me.Height - 1)
End If
End Sub
Feature 3: XP style images
This is the most fun part! When you look really close at an XP style button you will notice that there are some very neat effects for the images. In a normal state (no mouse over the button), a button displays a picture with slightly brighter colors than normal. When you move the mouse over the button, the pictures recieve shadow and will be displayed in normal colors (darker than before). When you press the button, the picture loses its shadow, but is still displayed in darker (normal) colors. The control only needs 1 picture, and generates the other 2 needed by code.
Here is an example of a picture in the 3 possible states:
Normal, with smooth, brighter colors.
Raised, with darker colors and shadow.
Pressed, with darker colors, no shadow.
First I needed a function to calculate the color shifts to the brighter colors (I found the formula on www.vbsmart.com):
Private Function TransformColor(ByVal x As Long) As Long
Return 76 - Int((x + 32) / 64) * 19 + x
End Function
The function to create the brighter image is:
Private Function GetSmoothImage(ByVal image As Image) As Image
Dim bmp As New Bitmap(image)
Dim x As Integer, y As Integer
For x = 0 To bmp.Width - 1
For y = 0 To bmp.Height - 1
Dim oldColor As Color = bmp.GetPixel(x, y)
If Not oldColor.Equals(Color.FromArgb(0, 0, 0, 0)) Then
Dim newColor As Color = _
Color.FromArgb(TransformColor(oldColor.R), _
TransformColor(oldColor.G), _
TransformColor(oldColor.B))
bmp.SetPixel(x, y, newColor)
End If
Next
Next
Return bmp
End Function
To generate the image for the button when the mouse is over it, first the image is converted to black and white (in a gray color). Then the original image is painted over it, but 2 pixels up and to the right. Like this you get a nice dropdown shadow effect:
Private Function GetRaisedImage(ByVal image As Image) As Image
Dim bmp As New Bitmap(image)
Dim newBmp As New Bitmap(bmp.Width + 2, bmp.Height + 2)
Dim x As Integer, y As Integer
For x = 0 To bmp.Width - 1
For y = 0 To bmp.Height - 1
Dim oldcolor As Color = bmp.GetPixel(x, y)
If oldcolor.Equals(Color.FromArgb(0, 0, 0, 0)) Then
newBmp.SetPixel(x + 2, y + 2, Color.Transparent)
Else
newBmp.SetPixel(x + 2, y + 2, Color.Gray)
End If
Next
Next
Dim g As Graphics = Graphics.FromImage(newBmp)
g.DrawImage(image, 0, 0)
Return newBmp
End Function
Finally, the image needed when the button is pressed, is equal to the original image:
Private Function GetDownImage(ByVal image As Image) As Image
Return _image
End Function
Other features
Some other features that are built into this control, but which I will not explain here are: text alignment, different border colors and image margin. You can find the code in the source project.
Features for the future
You can use this control already, because it has all the needed functionality. But there are some nice-to-have features that will be implemented somewhere in the (near?) future: image alignment, .ICO file type support, ... If you have other needs or ideas, please let them know!