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

A simple XP/VS.NET style button control

0.00/5 (No votes)
10 Jan 2003 1  
Why another button control? Because I searched the net for a control that would mimic the XP/VS.NET style buttons, but I couldn't find a decent one. I think this button has all needed functionality: cool style, shortcut keys, icons, alignment, ...

Sample Image - top.jpg

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
            'BINGO!

            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
    'Not needed

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!

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