Click here to Skip to main content
15,867,939 members
Articles / Desktop Programming / Windows Forms
Article

WinForms VB.NET Picture Hover Button

Rate me:
Please Sign up or sign in to vote.
4.04/5 (11 votes)
14 Jan 2005CPOL3 min read 117K   2.7K   42   15
Hover button with picture and font that changes with MouseOver.

Introduction

This is a hover button/hover control, that allows for a lot of flexibility as far as look and feel is concerned. You can set the location of the text and the image, as well as the image that is shown when the mouse is over the control. The example uses a VB.NET WinForms UserControl as the base for the control. If you're not experienced with building user controls then this is a great place to start. Looking at the guts of this control you'll learn some of the basics such as how to make a control a container for other controls, how to draw on the control using the Graphics class.

Functionality

The control allows you to use it as a button, or just a container, or simply a hover control. The hovering effect is managed by way of a timer. This is more reliable than using the MouseLeave or MouseEnter events. Each of those events may or may not fire depending on the speed of the mouse over the control. So if you do not use a timer for handling the hover effects, you may end up with a control that has the hover effect applied, but it never goes away because the MouseLeave event was never fired.

Capabilities

  • Can be in a selected state with a selected color defined.
  • Text ForeColor can be a specified color on Hover.
  • Image can be defined for Hover effect.
  • Image can be defined for regular, or non-hover effects.
  • Hover color can be defined. So the control's BackColor looks as if it has changed when the mouse is over the control.
  • Set the border color.
  • Define whether to view the border or not.
  • Define a group of buttons by setting the "Group" string value. This will select or unselect all the buttons with the same "Group" value on the current parent container.
  • Select or unselect all the buttons on the same parent container.
  • Position the text wherever you want on the control using the ContentAlignment enumeration as is currently used for the Label control.
  • Position the image anywhere on the control using the ContentAlignment enumeration as is currently used for the Label control.
  • Use the control as a container for other controls.

Construction

Add a UserControl to your project. Set some of the initial Imports statements as well as OPTION STRICT, etc.

VB
Option Strict On
Option Explicit On 

Imports System.ComponentModel
Imports System.ComponentModel.Design

At the top of the class, add some attributes that define how the control operates:

VB
' DefaultEvent("Click"), This sets the default event when double-clicking
'                       the control in design-mode.
' DefaultProperty("Text"), This will set the default
'                       property for the property inspector
'                       in design-mode.
'
' This attribute makes this control a container for
'                       other controls.
' Designer("System.Windows.Forms.Design.ParentControlDesigner, 
                           System.Design", GetType(IDesigner))
'
<DESIGNER("SYSTEM.WINDOWS.FORMS.DESIGN.PARENTCONTROLDESIGNER, 
                  DefaultProperty(?Text?) DefaultEvent(?Click?), 
                  GetType(IDesigner)), _ System.Design?,> _
Public Class PictureHoverButton
    Inherits System.Windows.Forms.UserControl

Next, in Sub New, set the styles for the control. This manages how the control functions specifically in the area of how to draw the control and what it supports:

VB
' This draws the control whenever it is resized
setstyle(ControlStyles.ResizeRedraw, True)

' This supports mouse movement such as the mouse wheel
setstyle(ControlStyles.UserMouse, True)

' This allows the control to be transparent
setstyle(ControlStyles.SupportsTransparentBackColor, True)

' This helps with drawing the control so that it doesn't flicker
Me.SetStyle(ControlStyles.DoubleBuffer _
  Or ControlStyles.UserPaint _
  Or ControlStyles.AllPaintingInWmPaint, _
  True)

' This updates the styles
Me.UpdateStyles()

Override the OnPaint event for the control. This is where the magic happens. This is where your control is your canvas, and you're the artist.

VB
Protected Overrides Sub OnPaint(ByVal pe As System.Windows.Forms.PaintEventArgs)
    MyBase.OnPaint(pe)
    Dim TopMargin As Integer
    Dim g As Graphics = pe.Graphics
    Dim DrawHover As Boolean

    _HoverRectangle = Nothing
    _HoverRectangle = New Rectangle(0, 0, Me.Width, Me.Height)


    ' The mouse is hovering over the control
    If _HasFocus Then
        If Me.Selected Then
            Dim rec As New Rectangle(0, 0, Me.Width, Me.Height)
            Dim b As New SolidBrush(Me.SelectedColor)
            g.FillRectangle(b, rec)
        Else
            ' Make sure the color is not Nothing, or Empty
            ' which is the equivalent to nothing for a color.
            If Not HoverColor.Equals(Color.Empty) Then
                Dim rec As New Rectangle(0, 0, Me.Width, Me.Height)
                Dim b As New SolidBrush(Me.HoverColor)
                g.FillRectangle(b, rec)
            End If
        End If

        ' Draw the Hover image
        If Not Me.Selected Then
            DrawHover = True
        End If
    Else
        If Me.Selected Then
            Dim rec As New Rectangle(0, 0, Me.Width, Me.Height)
            Dim b As New SolidBrush(Me.SelectedColor)
            g.FillRectangle(b, rec)
        End If
    End If

    Dim ptImage As Point
    ' Used to hold the dimensions of the current image
    Dim iWidth As Integer
    Dim iHeight As Integer
    Dim iCenter As Integer
    If DrawHover Then
        If Not Me.HoverImage Is Nothing Then
            iWidth = Me.HoverImage.Width
            iHeight = Me.HoverImage.Height
        Else
            If Not Me.Image Is Nothing Then
                iWidth = Me.Image.Width
                iHeight = Me.Image.Height
            End If
        End If
    Else
        If Not Me.Image Is Nothing Then
            iWidth = Me.Image.Width
            iHeight = Me.Image.Height
        End If
    End If

    ' Make sure we even need to draw an image to begin
    ' with. There may not be any images in this control.
    If Not iHeight = 0 Then
        ' Ge the position of the image
        Select Case ImageAlign
            Case ContentAlignment.BottomCenter
                ptImage =
                   New Point(Convert.ToInt32((Me.Width / 2) - (iWidth / 2)),
                                                 (Me.Height - iHeight) - 3)
            Case ContentAlignment.BottomLeft
                ptImage = New Point(5, (Me.Height - iHeight) - 3)
            Case ContentAlignment.BottomRight
                ptImage = New Point((Me.Width - iWidth) - 5,
                                       (Me.Height - iHeight) - 3)
            Case ContentAlignment.MiddleCenter
                ptImage =
                    New Point(Convert.ToInt32((Me.Width / 2) - (iWidth / 2)),
                           Convert.ToInt32((Me.Height / 2) - (iHeight / 2)))
            Case ContentAlignment.MiddleLeft
                ptImage =
                  New Point(5, Convert.ToInt32((Me.Height / 2) - (iHeight / 2)))
            Case ContentAlignment.MiddleRight
                ptImage = New Point((Me.Width - iWidth) - 5,
                               Convert.ToInt32((Me.Height / 2) - (iHeight / 2)))
            Case ContentAlignment.TopCenter
                ptImage =
                    New Point(Convert.ToInt32((Me.Width / 2) - (iWidth / 2)), 5)
            Case ContentAlignment.TopLeft
                ptImage = New Point(5, 5)
            Case ContentAlignment.TopRight
                ptImage = New Point((Me.Width - iWidth) - 5, 5)
        End Select

        If DrawHover Then
            If Not Me.HoverImage Is Nothing Then
                g.DrawImage(Me.HoverImage, ptImage.X, ptImage.Y,
                      Me.HoverImage.Width, Me.HoverImage.Height)
            Else
                If Not Me.Image Is Nothing Then
                    g.DrawImage(Me.Image, ptImage.X, ptImage.Y,
                                Me.Image.Width, Me.Image.Height)
                End If
            End If
        Else
            If Not Me.Image Is Nothing Then
                g.DrawImage(Me.Image, ptImage.X, ptImage.Y,
                                Me.Image.Width, Me.Image.Height)
            End If
        End If
    End If

    ' Get the dimensions of the text.
    ' This will return a SizeF object that has height, width, etc.
    Dim ptSize As SizeF = g.MeasureString(Text, Font)

    Dim ptF As New PointF
    ' Get the location to set the Text.
    Select Case Me.TextAlign
        Case ContentAlignment.BottomCenter
            ptF.Y = Me.Height
            ptF.Y -= ptSize.Height
            ptF.X = Convert.ToInt32(Me.Width / 2)
            ptF.X -= ptSize.Width / 2

        Case ContentAlignment.BottomLeft
            ptF.Y = Me.Height
            ptF.Y -= ptSize.Height
            ptF.X = 2

        Case ContentAlignment.BottomRight
            ptF.Y = Me.Height
            ptF.Y -= ptSize.Height
            ptF.X = Me.Width
            ptF.X -= ptSize.Width

        Case ContentAlignment.MiddleCenter
            ptF.Y = Convert.ToInt32(Me.Height / 2)
            ptF.Y -= ptSize.Height / 2
            ptF.X = Convert.ToInt32(Me.Width / 2)
            ptF.X -= ptSize.Width / 2

        Case ContentAlignment.MiddleLeft
            ptF.Y = Convert.ToInt32(Me.Height / 2)
            ptF.Y -= ptSize.Height / 2
            ptF.X = 0

        Case ContentAlignment.MiddleRight
            ptF.Y = Convert.ToInt32(Me.Height / 2)
            ptF.Y -= ptSize.Height / 2
            ptF.X = Me.Width
            ptF.X -= ptSize.Width

        Case ContentAlignment.TopCenter
            ptF.Y = 0
            ptF.X = Convert.ToInt32(Me.Width / 2)
            ptF.X -= ptSize.Width / 2

        Case ContentAlignment.TopLeft
            ptF.Y = 0
            ptF.X = 0

        Case ContentAlignment.TopRight
            ptF.Y = 0
            ptF.X = Me.Width
            ptF.X -= ptSize.Width
    End Select

    If _HasFocus AndAlso Not Me.Selected Then
        ' Draw the Text for the control using the HoverForeColor
        If Not Me.HoverForeColor.Equals(Color.Empty) Then
            g.DrawString(Me.Text, Me.Font,
                        New SolidBrush(Me.HoverForeColor), ptF)
        Else
            g.DrawString(Me.Text, Me.Font,
                        New SolidBrush(Me.ForeColor), ptF)
        End If
    Else
        ' Draw the Text for the control
        g.DrawString(Me.Text, Me.Font,
                        New SolidBrush(Me.ForeColor), ptF)
    End If

    ' Draw the border
    If Border Then
        If Not BorderColor.Equals(Color.Empty) Then
            Dim linePen As New Pen(New SolidBrush(_BorderColor), 1)
            g.DrawRectangle(linePen, New Rectangle(0, 0, Me.Width - 1,
                                                      Me.Height - 1))
        End If
    End If
End Sub

Building custom or UserControls are fun and easy once you get the basics down. This control still has lots of room for improvement such as setting the hover or backcolor as gradient, etc.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) BOCA Software Technologies, Inc.
United States United States
.NET Developer in Garner, North Carolina. Specializing in WinForms development in C#, VB.Net.

CEO/Founder BOCA Software Technologies, Inc.

Comments and Discussions

 
QuestionNice Control Pin
Mc Gwyn17-Oct-14 2:04
Mc Gwyn17-Oct-14 2:04 
Questionthanks Pin
Member 1007318130-May-13 22:49
Member 1007318130-May-13 22:49 
QuestionHow do you change the to context back once you leave the hover button Pin
Member 365498522-Feb-10 9:07
professionalMember 365498522-Feb-10 9:07 
QuestionVS 2008 Pin
Member 13500486-Jan-09 19:57
Member 13500486-Jan-09 19:57 
AnswerRe: VS 2008 Pin
Victor Boba7-Jan-09 12:45
Victor Boba7-Jan-09 12:45 
AnswerRe: VS 2008 Pin
Member 135004812-Jan-09 19:35
Member 135004812-Jan-09 19:35 
GeneralSad Pin
tongdo27-Jun-08 11:43
tongdo27-Jun-08 11:43 
GeneralRe: Sad Pin
Victor Boba27-Jun-08 11:49
Victor Boba27-Jun-08 11:49 
GeneralRe: Sad Pin
tongdo4-Jul-08 7:00
tongdo4-Jul-08 7:00 
Generalit not work properly Pin
ram krishna pattnayak8-Feb-07 0:22
ram krishna pattnayak8-Feb-07 0:22 
AnswerRe: it not work properly Pin
naiba1918-Dec-08 23:14
naiba1918-Dec-08 23:14 
i've got same error
you can rewrite a part of code like this:

ADD This part of code (where XCheckBox is the name of your coustum control):
Delegate Function GetPointToClientCallback(ByVal control As XCheckBox, ByVal mousePoz As Point) As Point

    Private Function GetPointToClient(ByVal control As XCheckBox, ByVal mousePoz As Point) As Point
        If control.InvokeRequired Then
            Dim d As New GetPointToClientCallback(AddressOf GetPointToClient)
            Return Me.Invoke(d, New Object() {control, mousePoz})
        Else
            Return control.PointToClient(mousePoz)
        End If
    End Function

Change the line
e = PointToClient(Windows.Forms.Cursor.Position)

INTO:
e = GetPointToClient(Me, Cursor.Position)

GeneralRe: it not work properly Pin
Member 435063318-Feb-09 20:03
Member 435063318-Feb-09 20:03 
AnswerAdapting to .NET 2010 Pin
AnyPick3-Nov-10 4:12
AnyPick3-Nov-10 4:12 
QuestionWrap text Pin
Nicola Gennaro7-Sep-06 1:09
Nicola Gennaro7-Sep-06 1:09 
GeneralGreat! But improvements needed! Pin
nmg19616-Feb-05 4:36
nmg19616-Feb-05 4:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.