Windows Phone sports a very tight but distinct and carefully balanced color palette. This palette is, however, well suited for many other applications where you need a modern appearance with the typical flat design introduced with Windows 8.
The palette may be somewhat familiar to you, as I have previously used it in another article:
Modern/Metro style message box and input box for Microsoft Access 2013
If you plan to use the palette for an application, you soon get tired of converting the color values back and forth. So, to ease this task, I've created a single-form application where you can:
As you may expect, the layout is extremely simple:
If all you need is exactly this - select and pick a color - just run the application and go ahead.
That said, the construction of the palette could be applied to other areas, so read on.
The source of the palette is the enumeration:
' Windows Phone colour enumeration.
Public Enum wpThemeColor
' Official colour names from WP8.
Lime = &HC4A4&
Green = &H17A960
Emerald = &H8A00&
Teal = &HA9AB00
Cyan = &HE2A11B
Cobalt = &HEF5000
Indigo = &HFF006A
Violet = &HFF00AA
Pink = &HD072F4
Magenta = &H7300D8
Crimson = &H2500A2
Red = &H14E5&
Orange = &H68FA&
Amber = &HAA3F0
Yellow = &HC8E3&
Brown = &H2C5A82
Olive = &H64876D
Steel = &H87766D
Mauve = &H8A6076
Sienna = &H2D52A0
' Colour name aliases from WP7.5
Viridian = &HA9AB00
Blue = &HE2A11B
Purple = &HFF00AA
Mango = &H68FA&
' Used for black in popups.
Darken = &H1D1D1D
' Additional must-have names for grey scale.
Black = &H0&
DarkGrey = &H3F3F3F
Grey = &H7F7F7F
LightGrey = &HBFBFBF
White = &HFFFFFF
End Enum
However, this is of little use as is because, for any practical use in Access and VBA, other formats are required.
For example, by default, Access uses the #AABBCC format in the Format property of the Property sheet.
Also, in VBA you cannot list the values of an enumeration other than from lowest to highest. Thus, as these values cover from Black to White, all possible color values will be tested. While this can easily be done:
' Loops all(!) possible color values and prints those of the
' Windows Phone Theme Colors.
' This will take nearly 30 seconds.
'
' 2017-04-21. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function ListColors()
Dim Color As wpThemeColor
For Color = wpThemeColor.Black To wpThemeColor.White
If IsWpThemeColor(Color) Then
Debug.Print Color, LiteralWpThemeColor(Color)
End If
Next
End Function
it takes about 30 seconds! Far too long to wait for a palette to show up.
To speed it up, another method is used that fills an array with the color values:
' Fill array ColorPalette with the values of wpThemeColor.
'
' 2017-04-21. Gustav Brock, Cactus Data ApS, CPH.
'
Private Sub LoadColors()
Dim Colors(0 To 29) As Long
Dim Index As Long
If IsEmpty(ColorPalette) Then
For Index = LBound(Colors) To UBound(Colors)
Select Case Index
Case 0
Colors(Index) = wpThemeColor.Lime
Case 1
Colors(Index) = wpThemeColor.Green
Case 2
Colors(Index) = wpThemeColor.Emerald
Case 3
Colors(Index) = wpThemeColor.Teal
Case 4
Colors(Index) = wpThemeColor.Cyan
Case 5
Colors(Index) = wpThemeColor.Cobalt
Case 6
Colors(Index) = wpThemeColor.Indigo
Case 7
Colors(Index) = wpThemeColor.Violet
Case 8
Colors(Index) = wpThemeColor.Pink
Case 9
Colors(Index) = wpThemeColor.Magenta
Case 10
Colors(Index) = wpThemeColor.Crimson
Case 11
Colors(Index) = wpThemeColor.Red
Case 12
Colors(Index) = wpThemeColor.Orange
Case 13
Colors(Index) = wpThemeColor.Amber
Case 14
Colors(Index) = wpThemeColor.Yellow
Case 15
Colors(Index) = wpThemeColor.Brown
Case 16
Colors(Index) = wpThemeColor.Olive
Case 17
Colors(Index) = wpThemeColor.Steel
Case 18
Colors(Index) = wpThemeColor.Mauve
Case 19
Colors(Index) = wpThemeColor.Sienna
Case 20
Colors(Index) = wpThemeColor.Darken
Case 21
Colors(Index) = wpThemeColor.Viridian
Case 22
Colors(Index) = wpThemeColor.Blue
Case 23
Colors(Index) = wpThemeColor.Purple
Case 24
Colors(Index) = wpThemeColor.Mango
Case 25
Colors(Index) = wpThemeColor.Black
Case 26
Colors(Index) = wpThemeColor.DarkGrey
Case 27
Colors(Index) = wpThemeColor.Grey
Case 28
Colors(Index) = wpThemeColor.LightGrey
Case 29
Colors(Index) = wpThemeColor.White
End Select
Next
End If
ColorPalette = Colors()
End Sub
Now, with a tiny helper function, PaletteColor, a simple loop can set the BackGround of the color rectangles ("Box1" etc.) in a snap:
' Returns the color value of Index from array ColorPalette
' which holds the Windows Phone Theme Colors.
' If ColorPalette is empty, LoadColors is called to fill it.
'
' 2017-04-21. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function PaletteColor( _
ByVal Index As Integer) _
As Long
If IsEmpty(ColorPalette) Then
' Fill array ColorPalette.
LoadColors
End If
PaletteColor = ColorPalette(Index)
End Function
Private Sub Form_Open(Cancel As Integer)
Dim Index As Integer
' Set colour palette.
For Index = 0 To 20
Me("Box" & CStr(Index + 1)).BackColor = PaletteColor(Index)
Me("Name" & CStr(Index + 1)).Value = LiteralWpThemeColor(PaletteColor(Index))
Me("Css" & CStr(Index + 1)).Value = RGBHex(PaletteColor(Index))
Me("Vba" & CStr(Index + 1)).Value = PaletteColor(Index)
Me("Hex" & CStr(Index + 1)).Value = "&H" & Hex(PaletteColor(Index))
Next
End Sub
The same loop is used to set the color name and the different value formats. These values are derived from two helper functions:
' Returns the literal name of the passed colour value if
' it is one of the Windows Phone Theme Colors.
'
' 2017-04-21. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function LiteralWpThemeColor( _
ByVal Color As wpThemeColor) _
As String
Dim Name As String
Select Case Color
Case wpThemeColor.Lime
Name = "Lime"
Case wpThemeColor.Green
Name = "Green"
Case wpThemeColor.Emerald
Name = "Emerald"
Case wpThemeColor.Teal
Name = "Teal"
Case wpThemeColor.Cyan
Name = "Cyan"
Case wpThemeColor.Cobalt
Name = "Cobalt"
Case wpThemeColor.Indigo
Name = "Indigo"
Case wpThemeColor.Violet
Name = "Violet"
Case wpThemeColor.Pink
Name = "Pink"
Case wpThemeColor.Magenta
Name = "Magenta"
Case wpThemeColor.Crimson
Name = "Crimson"
Case wpThemeColor.Red
Name = "Red"
Case wpThemeColor.Orange
Name = "Orange"
Case wpThemeColor.Amber
Name = "Amber"
Case wpThemeColor.Yellow
Name = "Yellow"
Case wpThemeColor.Brown
Name = "Brown"
Case wpThemeColor.Olive
Name = "Olive"
Case wpThemeColor.Steel
Name = "Steel"
Case wpThemeColor.Mauve
Name = "Mauve"
Case wpThemeColor.Sienna
Name = "Sienna"
Case wpThemeColor.Viridian
Name = "Viridian"
Case wpThemeColor.Blue
Name = "Blue"
Case wpThemeColor.Purple
Name = "Purple"
Case wpThemeColor.Mango
Name = "Mango"
Case wpThemeColor.Darken
Name = "Darken"
Case wpThemeColor.Black
Name = "Black"
Case wpThemeColor.DarkGrey
Name = "DarkGrey"
Case wpThemeColor.Grey
Name = "Grey"
Case wpThemeColor.LightGrey
Name = "LightGrey"
Case wpThemeColor.White
Name = "White"
End Select
LiteralWpThemeColor = Name
End Function
' Returns the CSS hex representation of a decimal RGB value
' with or without a leading octothorpe.
'
' Example:
' CSSValue = RGBHex(813466)
' ' CSSValue = "#9A690C"
' CSSValue = RGBHex(813466, True)
' ' CSSValue = "9A690C"
'
' 2017-03-26. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function RGBHex( _
ByVal Color As Long, _
Optional ByVal NoPrefix As Boolean) _
As String
' Format of RGB hex strings.
Const RGBPrefix As String = "#"
Dim Red As Integer
Dim Green As Integer
Dim Blue As Integer
Dim HexRGB As String
RGBComponent Color, , Red, Green, Blue
If Not NoPrefix Then
' Set prefix.
HexRGB = RGBPrefix
End If
' Assemble compound string with leading zeroes for small values.
HexRGB = HexRGB & _
Right("0" & Hex(Red), 2) & _
Right("0" & Hex(Green), 2) & _
Right("0" & Hex(Blue), 2)
RGBHex = HexRGB
End Function
Nothing fancy here.
Neither does it take much to select and copy a value of a TextBox to the clipboard:
' Select full content.
TextBox.SelStart = 0
TextBox.SelLength = Len(TextBox.Value)
' Display the clicked value.
TextBox.Parent!CopyClicked.Value = TextBox.Value
' Copy the clicked value to the clipboard.
DoCmd.RunCommand acCmdCopy
However, we have 3 x 20 textboxes so you would have to write 60 calls to such a helper function. A nightmare.
Now is the time to call for WithEvents
If the purpose and usage of WithEvents is new to you, sadly the official documentation is poor and sparse, nearly missing; but a good intro by John Colby can be found here: Object wrappers and Event sinks
Here we have too many controls to write them up one by one as in JCs' demo, so a collection is used to get hold of them.
This adds up in this class module:
Option Explicit
' Helper class for form Palette for event handling of textboxes.
' 2017-04-19. Gustav Brock, Cactus Data ApS, CPH.
' Version 1.0.0
' License: MIT.
' *
Private Const EventProcedure As String = "[Event Procedure]"
Private WithEvents ClassTextBox As Access.TextBox
Public Sub Initialize(ByRef TextBox As Access.TextBox)
Set ClassTextBox = TextBox
ClassTextBox.OnClick = EventProcedure
End Sub
Public Sub Terminate()
Set ClassTextBox = Nothing
End Sub
Private Sub ClassTextBox_Click()
' Select full content.
ClassTextBox.SelStart = 0
ClassTextBox.SelLength = Len(ClassTextBox.Value)
' Display the clicked value.
ClassTextBox.Parent!CopyClicked.Value = ClassTextBox.Value
' Copy the clicked value to the clipboard.
DoCmd.RunCommand acCmdCopy
End Sub
Yes, that is the complete module.
And to load and unload the class module in the form, this is the code:
Option Explicit
' Form to display the Windows Phone 7.5/8.0 colour theme.
' Also works as a basic example of implementing WithEvents for a form.
' 2017-04-19. Gustav Brock, Cactus Data ApS, CPH.
' Version 1.0.0
' License: MIT.
' *
Private ControlCollection As Collection
Private Sub Form_Load()
' Load events for all colour value textboxes.
Dim EventProcedure As ClassTextboxSelect
Dim Control As Access.Control
Set ControlCollection = New Collection
For Each Control In Me.Controls
If Control.ControlType = acTextBox Then
Set EventProcedure = New ClassTextboxSelect
EventProcedure.Initialize Control
ControlCollection.Add EventProcedure, Control.Name
End If
Next
Set EventProcedure = Nothing
Set Control = Nothing
End Sub
Private Sub Form_Unload(Cancel As Integer)
' Unload events for all colour value textboxes.
Dim EventProcedure As ClassTextboxSelect
For Each EventProcedure In ControlCollection
EventProcedure.Terminate
Next
Set EventProcedure = Nothing
Set ControlCollection = Nothing
End Sub
Again, this is the full code.
Compare that to write 60 times a set of code lines.
The form is now ready for use. Open it and click any value - and that value will be copied to the clipboard and also displayed in the textbox in the lower right corner.
The attached file and its code modules also contains a couple of helper functions that can prove useful, though not used here.
First, this function will check if a color value is equal to one of the palette colors:
' Returns True if the passed colour value is one of the
' Windows Phone Theme Colors.
'
' 2017-04-21. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function IsWpThemeColor(ByVal Color As Long) As Boolean
Dim Item As Integer
Dim IsColor As Boolean
If IsEmpty(ColorPalette) Then
' Fill public array ColorPalette.
LoadColors
End If
For Item = LBound(ColorPalette) To UBound(ColorPalette)
If Color = ColorPalette(Item) Then
IsColor = True
Exit For
End If
Next
IsWpThemeColor = IsColor
End Function
And the first of these two functions will convert a CSS color value of the format #AABBCC to a color value of VBA, while the other will split a VBA color value into its R, G, and B components.
Please study the in-line comments for typical usage:
' Returns the numeric RGB value from an CSS RGB hex representation.
' Will accept strings with or without a leading octothorpe.
'
' Examples:
' Color = RGBCompound("#9A690C")
' ' Color = 813466
' Color = RGBCompound("9A690C")
' ' Color = 813466
'
' 2017-03-26. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function RGBCompound( _
ByVal HexRGB As String) _
As Long
' Format of RGB hex strings.
Const RGBPrefix As String = "#"
Const Length As Integer = 6
' Format of Hex values.
Const HexPrefix As String = "&H"
Dim Start As Integer
Dim Color As Long
If Mid(HexRGB, 1, 1) = RGBPrefix Then
Start = 1
End If
If Len(HexRGB) = Start + Length Then
Color = RGB( _
HexPrefix & Mid(HexRGB, Start + 1, 2), _
HexPrefix & Mid(HexRGB, Start + 3, 2), _
HexPrefix & Mid(HexRGB, Start + 5, 2))
End If
RGBCompound = Color
End Function
' Calculate discrete RGB colours from a composite colour value and
' return one component.
' Also, by reference, return all components.
'
' Examples:
' Simple print of the components:
'
' SomeColor = 813466
' RGBComponent SomeColor
' ' Debug Print:
' ' 154 105 12
'
' Get one component from a colour value:
'
' Dim SomeColor As Long
' Dim Green As Integer
' SomeColor = 13466
' Green = RGBComponent(SomeColor, vbGreen)
' ' Green -> 52
'
' Get all components from a colour value:
'
' Dim SomeColor As Long
' Dim Red As Integer
' Dim Green As Integer
' Dim Blue As Integer
' SomeColor = 813466
' RGBComponent SomeColor, , Red, Green, Blue
' ' Red -> 154
' ' Green -> 105
' ' Green -> 12
'
' 2017-03-26. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function RGBComponent( _
ByVal RGB As Long, _
Optional ByVal Component As Long, _
Optional ByRef Red As Integer, _
Optional ByRef Green As Integer, _
Optional ByRef Blue As Integer) _
As Integer
Dim Color As Long
If RGB <= 0 Then
' Return Black.
Red = 0
Green = 0
Blue = 0
Else
' Extract the discrete colours from the composite RGB.
Red = RGB And vbRed
Green = (RGB And vbGreen) / &H100
Blue = (RGB And vbBlue) / &H10000
' Return chosen colour component.
Select Case Component
Case vbRed
Color = Red
Case vbGreen
Color = Green
Case vbBlue
Color = Blue
Case Else
Color = vbBlack
End Select
End If
' Debug.Print Red, Green, Blue
RGBComponent = Color
End Function
The current code can be found at GitHub: VBA.ModernTheme
It contains the separate modules and also the Access 2016 accdb-file.
The full code and the Access application is attached here: ModernTheme 1.0.1.zip
I hope you found this article useful. You are encouraged to ask questions, report any bugs or make any other comments about it below.
Note: If you need further "Support" about this topic, please consider using the Ask a Question feature of Experts Exchange. I monitor questions asked and would be pleased to provide any additional support required in questions asked in this manner, along with other EE experts.
Please do not forget to press the "Thumbs Up" button if you think this article was helpful and valuable for EE members.
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (5)
Commented:
Commented:
Author
Commented:/gustav
Commented:
I adapted my application to this and I could not believe how efficient and easy this was to do. I see myself deleting a HUGE amount of redundant code and using Class Module in the future. They have always intimidated me and quite frankly, I did not see the use of them until I needed something similar to what you did here. The link you provided to John Colby's Blog was spot-on and VERY informative.
A question on this method however, the particular functionality I am trying to achieve applies to Text and Combo boxes. Reading JC's Blog led me to believe that I would need another Class to handle each type of Object.
Did I comprehend that correctly or can I include more than one Object in this Class?
Great stuff!
John
Author
Commented:Or you can modify this check:
If Control.ControlType = acTextBox Then
to check for other control types as well. And then either apply the same or different methods.
Or do both. Or add more conditions; for example only apply a method to a control with a control source.
/gustav