"Classy" Excel UserForms

Add a Little Class to Excel's UserForms
This post shows how to, with a little class and very little coding, add color and dynamic effects to forms. This also offers new coders an opportunity to learn about class modules used for handling userform events.

Background
Excel’s user forms lack class (pun intended). By default they are dull and dead. They don’t have to be.

With a small class module, any Excel user form can be "classy". They can reflect your company’s branding. They can even add a little life by lighting up buttons as the mouse moves over, just like Excel’s ribbon controls.

Demo

Seeing is believing. So here is a short video demonstrating how clsForm transforms userforms and how easy it is to make your forms "classy".

NOTE! The video is a bit old. The links below point to a newer version of clsForm along with new documentation. The new version makes adding class to forms even easier.

So kick back. Watch the short video, then download the PDF using the links below. Like all BXL projects, everything is free. If you find this helpful, please like the video, post a comment, or perhaps a note on BXL's Facebook page. And as always, keep XL'n!

Implementing
We can implement clsForm from within a userform with just two lines of code, or attach clsForm to a userform from a module. I prefer adding the class in a userform's initialize event so when the form displays, the class activates simultaneously.

Example:
One way to implement this class on a userform takes two lines of code placed in the UserForm_Initialize procedure. Here is a sample:

Private Sub UserForm_Initialize()

' NOTE! Static - to keep in memory after this routine ends

Static FormClass As New clsForm

Set FormClass.UserForm = Me

End Sub

To create this we must first insert a class module (Insert > Class Module). Name it clsForm. Next copy all of these code segments to the class module.

Class Module Level Code
This first section creates variables that will be accessible by all routines in this class.

' Version: 12/10/19

' Save As: clsForm

' Description:Formats User Forms and Controls


' Date Ini Modification

' 06/21/13 CWH Initial Programming

' 07/10/14 CWH Version 2014.07

' 10/22/14 CWH Changed sRoutine to cRoutine

' 04/05/17 CWH Added flexibility in coloring


Option Explicit

' Private Properties

Const cModule As String = "clsForm" 'This module's name

Const Success As Boolean = False 'Successful Finish

Const Failure As Boolean = True 'Failed Finish

Const NoError As Long = 0 'No Error

Const LogError As Long = 997 'Log Error

Const RtnError As Long = 998 'Return Error

Const DspError As Long = 999 'Display Error


Private WithEvents oMsForm As UserForm 'Object for Form Events

Private WithEvents oFrame As Frame 'Object for Frame Events

Private WithEvents oCmdBtn As CommandButton 'Object for Command Button Events

Private WithEvents oTglBtn As ToggleButton 'Object for Toggle Button Events

Private WithEvents oImage As Image 'Object for Image Control Events

Private WithEvents oMltPag As Multipage 'Object for Multipage Events

Private oForm As Object 'Object for Form Properties

Dim dicCtrls As Object 'Controls that impact Glowing


Class Public Property
When the form is assigned to this class object, this class object finds all controls on the form and creates new instances of this class for each control

Public Property Set UserForm(ByVal oUserForm As Object)


' Description:Attach Userform to Class

' Inputs: oUserForm User form

' Outputs: *None

' Requisites: Routines Setup

' Example: *None

' Note! Object type "UserForm" does not expose all form properties.

' Examples include: Top, Left, Width, Height, and Caption.

' A generic object will. But a generic object does not expose

' any events. So to expose events AND all properties

' we pass the user form as a generic "Object" (for properties)

' and assign it to an MsForms.UserForm object (for events).


' Date Ini Modification

' 06/21/13 CWH Initial Programming


' Declarations

Const cRoutine As String = "UserForm"


' Error Handling Initialization

On Error GoTo ErrHandler


' Initialize Variables

If dicCtrls Is Nothing Then _

Set dicCtrls = CreateObject("Scripting.Dictionary")


' Procedure

Set oForm = oUserForm: Set oMsForm = oForm

Setup oForm


ErrHandler:

Select Case Err.Number

Case Is = NoError: 'Do nothing

Case Else:

Select Case DspErrMsg(cModule & "." & cRoutine)

Case Is = vbAbort: Stop: Resume 'Debug mode - Trace

Case Is = vbRetry: Resume 'Try again

Case Is = vbIgnore: 'End routine

End Select

End Select


End Function

Control Properties
When the form is assigned to this class object, this class object finds all controls on the form and creates new instances of this class for each control

Public Property Set Frame(ByVal Frame As Frame)

Set oFrame = Frame

End Property


Public Property Set Multipage(ByVal Multipage As Multipage)

Set oMltPag = Multipage

End Property


Public Property Set CommandButton(ByVal CommandButton As CommandButton)

Set oCmdBtn = CommandButton

End Property


Public Property Set ToggleButton(ByVal ToggleButton As ToggleButton)

Set oTglBtn = ToggleButton

End Property


Public Property Set Image(ByVal Image As Image)

Set oImage = Image

End Property

Event Handlers
These routines respond to MouseMoves over each object.

Remove glow effects from all controls on form when mouse is over the form and not any of the controls.

Private Sub oMsForm_MouseMove(ByVal Button As Integer, _

ByVal Shift As Integer, _

ByVal X As Single, _

ByVal Y As Single)


' Description:Sets all Command Buttons to "normal" color

' Inputs: Button Pressed Mouse button

' Shift State of the SHIFT, CTRL, and ALT keys

' X Mouse X

' Y Mouse Y

' Outputs: Me Success/Failure

' Requisites: *None

' Notes: http://msdn.microsoft.com/en-us/library/office/aa220909(v=office.11).aspx

' Example: *None (Event Handler)


' Date Ini Modification

' 06/21/13 CWH Initial Programming


' Declarations

Const cRoutine As String = "oMsForm_MouseMove"

Dim oCtrl As control


' Error Handling Initialization

On Error GoTo ErrHandler

' Procedure

For Each oCtrl In oForm.Controls

If TypeName(oCtrl) = "CommandButton" Then

oCtrl.BackColor = Color(crButton)

oCtrl.ForeColor = Color(crButtonFont)

End If

If TypeName(oCtrl) = "Image" Then

oCtrl.BackColor = Color(crButton)

oCtrl.BackStyle = fmBackStyleTransparent

End If

Next

ErrHandler:

Select Case Err.Number

Case Is = NoError: 'Do nothing

Case Else:

Select Case DspErrMsg(cModule & "." & cRoutine)

Case Is = vbAbort: Stop: Resume 'Debug mode - Trace

Case Is = vbRetry: Resume 'Try again

Case Is = vbIgnore: 'End routine

End Select

End Select


End Function

Remove glow effects from all controls in frame when mouse is over the frame and not any of the controls.

Private Sub oFrame_MouseMove(ByVal Button As Integer, _

ByVal Shift As Integer, _

ByVal X As Single, _

ByVal Y As Single)


' Description:Sets all Command Buttons to "normal" color

' Inputs: Button Pressed Mouse button

' Shift State of the SHIFT, CTRL, and ALT keys

' X Mouse X

' Y Mouse Y

' Outputs: Me Success/Failure

' Requisites: *None

' Example: *None (Event Handler)


' Date Ini Modification

' 06/09/14 CWH Initial Programming


' Declarations

Const cRoutine As String = "oFrame_MouseMove"

Dim oCtrl As control


' Error Handling Initialization

On Error GoTo ErrHandler

' Procedure

For Each oCtrl In oFrame.Controls

If TypeName(oCtrl) = "CommandButton" Then

oCtrl.BackColor = Color(crButton)

oCtrl.ForeColor = Color(crButtonFont)

End If

If TypeName(oCtrl) = "Image" Then

oCtrl.BackColor = Color(crButton)

oCtrl.BackStyle = fmBackStyleTransparent

End If

Next

ErrHandler:

Select Case Err.Number

Case Is = NoError: 'Do nothing

Case Else:

Select Case DspErrMsg(cModule & "." & cRoutine)

Case Is = vbAbort: Stop: Resume 'Debug mode - Trace

Case Is = vbRetry: Resume 'Try again

Case Is = vbIgnore: 'End routine

End Select

End Select


End Function

Make command buttons glow when the mouse is over them.

Private Sub oCmdBtn_MouseMove(ByVal Button As Integer, _

ByVal Shift As Integer, _

ByVal X As Single, _

ByVal Y As Single)


oCmdBtn.BackColor = Color(crButtonGlow)

oCmdBtn.ForeColor = Color(crButtonGlowFont)


End Sub

Make toggle buttons glow when the mouse is over them.

Private Sub oTglBtn_MouseMove(ByVal Button As Integer, _

ByVal Shift As Integer, _

ByVal X As Single, _

ByVal Y As Single)


oTglBtn.BackColor = Color(crButtonGlow)

oTglBtn.ForeColor = Color(crButtonGlowFont)


End Sub

Make Image controls glow when the mouse is over them.

Private Sub oImage_MouseMove(ByVal Button As Integer, _

ByVal Shift As Integer, _

ByVal X As Single, _

ByVal Y As Single)


oImage.BackColor = Color(crButtonGlow)

oImage.BackStyle = fmBackStyleOpaque


End Sub

Remove glow effects from all controls in the multipage when mouse is over the multipage and not any of the controls.

Private Sub oMltPag_MouseMove(ByVal Index As Long, _

ByVal Button As Integer, _

ByVal Shift As Integer, _

ByVal X As Single, _

ByVal Y As Single)


' Description:Sets all Command Buttons to "normal" color

' Inputs: Button Pressed Mouse button

' Shift State of the SHIFT, CTRL, and ALT keys

' X Mouse X

' Y Mouse Y

' Outputs: Me Success/Failure

' Requisites: *None

' Notes: http://msdn.microsoft.com/en-us/library/office/aa220909(v=office.11).aspx

' Example: *None (Event Handler)


' Date Ini Modification

' 06/21/13 CWH Initial Programming


' Declarations

Const cRoutine As String = "oMltPag_MouseMove"

Dim oCtrl As control


' Error Handling Initialization

On Error GoTo ErrHandler

' Procedure

For Each oCtrl In oMltPag.Parent.Controls

If TypeName(oCtrl) = "CommandButton" Then

oCtrl.BackColor = Color(crButton)

oCtrl.ForeColor = Color(crButtonFont)

End If

Next

ErrHandler:

Select Case Err.Number

Case Is = NoError: 'Do nothing

Case Else:

Select Case DspErrMsg(cModule & "." & cRoutine)

Case Is = vbAbort: Stop: Resume 'Debug mode - Trace

Case Is = vbRetry: Resume 'Try again

Case Is = vbIgnore: 'End routine

End Select

End Select


End Sub

Private Routines

This function is called when the UserForm property is set.

Private Function Setup(ByVal oForm As Object) As Boolean


' Description:Set backgrounds, fonts, and position

' Inputs: oForm User Form (as Object for Properties)

' Outputs: Me Success/Failure

' Requisites: Classes clsForm

' Example: ?Setup(oForm)


' Date Ini Modification

' 06/21/13 CWH Initial Development

' 04/05/17 CWH Allow crFrom to be a picture


' Declarations

Const cRoutine As String = "Setup"

Dim oCtrl As control

Dim oPage As control

Dim clsCtrl As clsForm


' Error Handling Initialization

On Error GoTo ErrHandler


' Procedure

ApyClr oForm, crForm

For Each oCtrl In oForm.Controls

Set clsCtrl = New clsForm

With oCtrl

Select Case TypeName(oCtrl)

Case Is = "TextBox"

If .Name = "txtErrMsg" Then

.BackStyle = fmBackStyleTransparent

.ForeColor = Color(crFormFont)

Else

ApyClr oCtrl, crLight

End If

Case Is = "ComboBox", "ListBox"

ApyClr oCtrl, crLight

Case Is = "CommandButton"

Set clsCtrl.CommandButton = oCtrl

Set dicCtrls(oCtrl.Name) = clsCtrl

ApyClr oCtrl, crButton

Case Is = "Image"

Set clsCtrl.Image = oCtrl

Set dicCtrls(oCtrl.Name) = clsCtrl

.BackColor = Color(crButton)

Case Is = "Frame"

Set clsCtrl.Frame = oCtrl

Set dicCtrls(oCtrl.Name) = clsCtrl

ApyClr oCtrl, crFrame

Case Is = "TabStrip"

.BackColor = Color(crForm)

.ForeColor = Color(crDark)

Case Is = "MultiPage"

Set clsCtrl.Multipage = oCtrl

Set dicCtrls(oCtrl.Name) = clsCtrl

ApyClr oCtrl, crForm

For Each oPage In .Pages

ApyClr oCtrl, crForm

Next

Case Is = "SpinButton", "ScrollBar"

ApyClr oCtrl, crButton

Case Is = "Label", "CheckBox", _

"OptionButton", "ToggleBotton"

ApyClr oCtrl, crForm

End Select

End With

Set clsCtrl = Nothing

Next

oForm.StartUpPosition = 3 'Windows Default

With Application

oForm.Left = .Left + .Width / 2 - oForm.Width / 2

oForm.Top = .Top + .Height / 2 - oForm.Height / 2

End With

ErrHandler:

Select Case Err.Number

Case Is = NoError: 'Do nothing

Case Else:

Select Case DspErrMsg(cModule & "." & cRoutine)

Case Is = vbAbort: Stop: Resume 'Debug mode - Trace

Case Is = vbRetry: Resume 'Try again

Case Is = vbIgnore: 'End routine

End Select

End Select


End Function


This is called by Setup()

Private Function ApyClr(ByVal oControl As Object, _

ByVal lColor As crRequestTypes) As Boolean


' Description:Apply color or picture to Control

' Inputs: oControl Control to set

' lColor Color Request

' Outputs: Me Success/Failure

' Requisites: Routines modGeneral.Color

' Example: ApyClr oForm, crForm


' Date Ini Modification

' 04/06/17 CWH Initial Development


' Declarations

Const cRoutine As String = "ApyClr"


' Error Handling Initialization

On Error GoTo ErrHandler

ApyClr = Failure


' Procedure

With oControl

.ForeColor = Color(lColor + 1)

If TypeName(Color(lColor)) = "Picture" Then

.Picture = Color(lColor)

.PictureAlignment = 2 'fmPictureAlignmentCenter

.PictureSizeMode = 0

.PictureTiling = True

Else

.BackColor = Color(lColor)

End If

If InStr(1, TypeName(oForm) & ",Image", TypeName(oControl)) > 0 Then

If TypeName(Color(crSkin)) = "Picture" Then

.Picture = Color(crSkin)

.PictureAlignment = 2 'fmPictureAlignmentCenter

.PictureSizeMode = 0

.PictureTiling = True

End If

End If

End With

ApyClr = Success

ErrHandler:

Select Case Err.Number

Case Is = NoError: 'Do nothing

Case Else:

Select Case DspErrMsg(cModule & "." & cRoutine)

Case Is = vbAbort: Stop: Resume 'Debug mode - Trace

Case Is = vbRetry: Resume 'Try again

Case Is = vbIgnore: 'End routine

End Select

End Select


End Function