Color()
Appearance is important.
If we want our first impressions to be impressive, we need to address color use. We see color usage before we see model structure and certainly before we see project functionality. We react to color without thinking. We are trained to recognize random colors and rainbow pallets as childish. The key to looking professional is to start with our client's color pallet. We can see this in their marketing materials and logos.
Color() was designed to help us apply a color pallet across all Excel objects: Worksheets, Tables, PivotTables, Charts, Slicers, User Forms, etc.. Color() provides a standard color number for a given Excel object. We tell it what object type we need a color for and Color() provides the appropriate color. In this way, all objects of the same type will have consistent colors matched to our workbook's color theme.
NOTE!
Color() is an old routine. It debuted before Excel had Styles (Microsoft keeps copying my ideas!) and long before most of my clients' Excel versions supported Styles. Today, we should apply Styles to much of what Color() addresses but I still use Color() in almost every project to apply corporate branding to things Styles does not address, such as user forms and user form elements. I also use Color() to create corporate branded Styles with BXL Format.
To tell Color() what object type we need a color for, we pass to Color() a Color Request Type which is an enumeration called crRequestTypes shown below.
Enum crRequestTypes 'Color Request Types
crReset
crLogo
crSkin
crForm
crFormFont
crFrame
crFrameFont
crButton
crButtonFont
crButtonGlow
crButtonGlowFont
crDark
crDarkFont
crLight
crLightFont
crAccentDark
crAccentDarkFont
crAccent
crAccentFont
crAccentlight
crAccentLightFont
crTableStyle
crPivotTableStyle
crSlicerStyle
crTimelineStyle
crBackground
crChartStyle
crChartColor
crChartColorFont
crChartArea
crPlotArea
crChartTitleLocation
crChartLegendLocation
crLogoPath
[_cr]
End Enum
crRequestTypes should be placed at the top of the module that contains the function: Color().
Color() contains an array of color defaults. Color() creates the array by splitting its constant, sDefault. If we want different theme colors applied to different objects we can change sDefault or we can use an optional Skin table. Below is a sample Skin table. If our workbook includes a table like this named Skin, Color() will use it instead of sDefault.
Function Color(ByVal ColorType As crRequestTypes, _
Optional ByVal oWorkbook As Workbook = Nothing) As Variant
' Description:Get a Color from Skin Table or Pallet
' Inputs: ColorType Color Request Type
' Outputs: Me Success:Color or Picture
' Failure:Null
' Requisites: Table: Skin (optional)
' Routines: me.Exists
' Routines: me.Tables
' Example: Selection.Interior.Color = Color(crAccent)
' Date Ini Modification
' 07/08/03 CWH Initial Development
' 06/03/14 CWH Added *DefaultTableStyle,*DefaultPivotTableStyle
' 09/04/14 CWH Better handling of Picture pathing
' 10/06/14 CWH Added oWorkbook Parameter
' 06/25/15 CWH Accommodated running Excel from illegal directory (ex. web)
' 12/16/15 CWH Changed how oWorkbook is determined when not sent
' 01/28/16 CWH Added ChartStyle and SlicerStyle
' 04/29/17 CWH Fixed problem when Skin.jpg is not found
' 06/30/17 CWH Accommodated old Skin tables
' 08/21/18 CWH Ditched Styles for Colors
' 09/06/18 CWH Reversed Backcolors for Fonts
' 11/02/18 CWH WTH? Can't access ThemeColorScheme if Workbook has protected sheets
' 04/01/20 CWH Added Timeline style
' 09/16/21 CWH Added clsSettings & crLogoPath
' Declarations
Const cRoutine As String = "Color"
Static dicColors As Object 'Color Dictionary
Static oLstWkb As Workbook 'Last Workbook
Static oSkin As ListObject 'Skin Table
Dim oStg As clsSettings 'Dactivate/Unprotect
Dim oLo As ListObject 'Current ListObject
Dim oLr As ListRow 'Current ListRow
Dim sKey As String 'Dictionary's Key
Dim sTyp As String 'Color Source Type
Dim sVal As String 'Color Source Value
Dim iRed As Integer 'Color's Red Component
Dim iGreen As Integer 'Color's Green Component
Dim iBlue As Integer 'Color's Blue Component
Dim lClr As Long 'Color Value
Dim v As Variant 'Generic Result
Const sDefaults As String = _
"Logo, T,Logo.gif; " & _
"Skin, P,Skin.jpg; " & _
"Form, C,3,3; " & _
"Frame, C,3,3; " & _
"Button, C,6,6; " & _
"Button Glow, C,7,7; " & _
"Dark, C,1,2; " & _
"Light, C,2,1; " & _
"Accent Dark, C,3,2; " & _
"Accent, C,4,4; " & _
"Accent Light, C,5,1; " & _
"TableStyle, T,*DefaultTableStyle;" & _
"PivotStyle, T,*DefaultPivotTableStyle;" & _
"SlicerStyle, T,*DefaultSlicerStyle;" & _
"TimelineStyle, T,*DefaultTimelineStyle;" & _
"Background, T,BackGround.jpg;" & _
"ChartStyle, T,201; " & _
"ChartColor, C,2,2; " & _
"ChartArea, T,ChartArea;" & _
"PlotArea, T,PlotArea; " & _
"Chart Title Location, T,Above; " & _
"Chart Legend Location, T,Right; " & _
"Logo Path, T,Logo.gif "
' Error Handling Initialization
On Error GoTo ErrHandler
Color = Null
' Check inputs and requisites
If oWorkbook Is Nothing Then Set oWorkbook = ActiveWorkbook
If ColorType = crReset Then Set oSkin = Nothing
If oSkin Is Nothing Then _
If Not Exists(Tables(oWorkbook), "Skin", oSkin) Then _
Exists Tables(ThisWorkbook), "Skin", oSkin
If oLstWkb Is Nothing Then Set oLstWkb = oWorkbook
' Initialize variables
If ColorType = crReset Then Set dicColors = Nothing
If dicColors Is Nothing Or oWorkbook.Name <> oLstWkb.Name Then
Set oStg = New clsSettings
Set oLstWkb = oWorkbook
Set dicColors = CreateObject("Scripting.Dictionary")
With oWorkbook
' Create default styles from sDefaults array
For Each v In Split(sDefaults, ";")
sKey = Trim(Split(v, ",")(0))
sTyp = Trim(Split(v, ",")(1))
sVal = Trim(Split(v, ",")(2))
Select Case sVal
Case Is = "*DefaultTableStyle": sVal = TblSty(oWorkbook, .DefaultTableStyle, "Table")
Case Is = "*DefaultPivotTableStyle": sVal = TblSty(oWorkbook, .DefaultPivotTableStyle, "Pivot")
Case Is = "*DefaultSlicerStyle": sVal = TblSty(oWorkbook, .DefaultSlicerStyle, "Slicer")
Case Is = "*DefaultTimelineStyle": sVal = TblSty(oWorkbook, .DefaultTimelineStyle, "Timeline")
End Select
Select Case sTyp
Case Is = "P" 'Picture
Set dicColors(sKey) = Nothing
If Not sVal Like "[A-Z]:*" And Not sVal Like "\\*" Then _
sVal = .Path & "\" & sVal
If Dir(sVal) <> vbNullString Then _
Set dicColors(sKey) = LoadPicture(sVal)
Case Is = "S" 'Style
dicColors(sKey) = .Styles(CLng(sVal)).Interior.Color
dicColors(sKey & ",Font") = .Styles(CLng(sVal)).Font.Color
Case Is = "C" 'Color
lClr = .Styles("Accent" & CLng(sVal)).Interior.Color
lClr = .Theme.ThemeColorScheme.Colors(CLng(sVal))
dicColors(sKey) = lClr
sVal = vbNullString: sVal = Split(v, ",")(3)
If sVal <> vbNullString Then
lClr = CLng(sVal)
Else
ColorCode2RGB lClr, iRed, iGreen, iBlue
lClr = IIf((iRed + iGreen + iBlue) / 3 < 128, 16777215, 0)
End If
dicColors(sKey & ",Font") = lClr
Case Is = "T" 'Text/Value
dicColors(sKey) = sVal
End Select
Next
' Create Styles from Skin table
If Exists(Tables(oWorkbook), "Skin", oLo) Then
For Each oLr In oLo.ListRows
With GetFLD(oLr, "Format")
sKey = GetFLD(oLr, "Name")
sVal = Trim(.Text)
dicColors(sKey) = sVal
Select Case sKey
Case Is = "TableStyle"
If Exists(oWorkbook.TableStyles, sVal) Then _
oWorkbook.DefaultTableStyle = sVal
Case Is = "PivotStyle"
If Exists(oWorkbook.TableStyles, sVal) Then _
oWorkbook.DefaultPivotTableStyle = sVal
Case Is = "SlicerStyle"
If Exists(oWorkbook.TableStyles, sVal) Then _
oWorkbook.DefaultSlicerStyle = sVal
Case Is = "TimelineStyle"
If Exists(oWorkbook.TableStyles, sVal) Then _
oWorkbook.DefaultTimelineStyle = sVal
Case Is = "Logo"
If sVal Like "*.*" Then
If Not sVal Like "[A-Z]:*" And Not sVal Like "\\*" Then _
sVal = oWorkbook.Path & "\" & sVal
If Dir(sVal) <> vbNullString Then
dicColors("Logo Path") = sVal
Set dicColors(sKey) = LoadPicture(sVal)
End If
Else
dicColors(sKey) = .Interior.Color
End If
Case Else
Set v = GetFLD(oLr, "Number")
If Not v Is Nothing Then _
If v.Value = vbNullString Then Set v = Nothing
If sVal Like "*.*" And v Is Nothing Then
If Not sVal Like "[A-Z]:*" And Not sVal Like "\\*" Then _
sVal = oWorkbook.Path & "\" & sVal
If Dir(sVal) <> vbNullString Then _
Set dicColors(sKey) = LoadPicture(sVal) Else _
dicColors(sKey) = .Interior.Color
Else
dicColors(sKey) = .Interior.Color
End If
dicColors(sKey & ",Font") = .Font.Color
End Select
End With
Next
End If
End With
End If
' Procedure
If ColorType <> crReset Then
If IsObject(dicColors.Items()(ColorType - 1)) Then _
Set Color = dicColors.Items()(ColorType - 1) Else _
Color = dicColors.Items()(ColorType - 1)
End If
ErrHandler:
Select Case Err.Number
Case Is = NoError: 'Do nothing
Case Is = 9: Resume Next 'Style not found
Case Is = 52, 75: Resume Next 'Illegal directory
Case Is = 1003, 1004: Resume Next 'Worksheet Protected
Case Is = -2147221080 'oLstWkb not yet set
Set oLstWkb = ActiveWorkbook
Resume
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
References:
DspErrMsg()
Exists()
Tables()
Dictionary Object