MS Office Style Color Picker in VB.NET

color_picker.jpg

Introduction

For a project I'm working on I needed something more stylish than the standard color dialog, which comes with  .NET, so I decided to make a color picker dialog of my own. I used the one found at Microsoft Office (for choosing the font color) as a source of inspiration (in fact, I shamelessly copied it) - I used exactly the same palette of 40 colors and the same "look and feel" - only the size and distance of the little color panels is a little different in my version.

Using the code

The code for the color dialog is very straightforward and offers nothing unusual. It has only about 200 lines of code and should be self-explaining. The control is a form with 40 small panel controls, which have event handlers for mouse messages attached to them. The constructor receives the coordinates of the point it is supposed to appear at as arguments (usually the calling button of the container form). When closed, the color dialog returns the chosen color. The dialog can be alternatively closed by hitting Escape or Enter (by using an "invisible" Escape button). In my small demo program the background color changes according to the chosen color. A standard color dialog is called from the "More colors..." button.


Public
Class ColorPaletteDialog
Inherits Form
Private max As Byte = 40
Private panel(40) As Panel
Private color(40) As Color = {Color.FromArgb(0, 0, 0), Color.FromArgb(153, 51, 0), Color.FromArgb(51, 51, 0),_
Color.FromArgb(0, 51, 0), Color.FromArgb(0, 51, 102), Color.FromArgb(0, 0, 128), Color.FromArgb(51, 51, 153),_
Color.FromArgb(51, 51, 51), Color.FromArgb(128, 0, 0), Color.FromArgb(255, 102, 0), Color.FromArgb(128, 128, 0),_
Color.FromArgb(0, 128, 0), Color.FromArgb(0, 128, 128), Color.FromArgb(0, 0, 255), Color.FromArgb(102, 102, 153),_
Color.FromArgb(128, 128, 128), Color.FromArgb(255, 0, 0), Color.FromArgb(255, 153, 0), Color.FromArgb(153, 204, 0),_
Color.FromArgb(51, 153, 102), Color.FromArgb(51, 204, 204), Color.FromArgb(51, 102, 255), Color.FromArgb(128, 0, 128),_
Color.FromArgb(153, 153, 153), Color.FromArgb(255, 0, 255), Color.FromArgb(255, 204, 0), Color.FromArgb(255, 255, 0),_
Color.FromArgb(0, 255, 0), Color.FromArgb(0, 255, 255), Color.FromArgb(0, 204, 255), Color.FromArgb(153, 51, 102),_
Color.FromArgb(192, 192, 192), Color.FromArgb(255, 153, 204), Color.FromArgb(255, 204, 153), Color.FromArgb(255, 255, 153),_
Color.FromArgb(204, 255, 204), Color.FromArgb(204, 255, 255), Color.FromArgb(153, 204, 255), Color.FromArgb(204, 153, 255), _
Color.FromArgb(255, 255, 255)}
Private colorName(40) As String = {"Black", "Brown", "Olive Green", "Dark Green", "Dark Teal", "Dark Blue", "Indigo",_
"Gray-80%", "Dark Red", "Orange", "Dark Yellow", "Green", "Teal", "Blue", "Blue-Gray", "Gray-50%", "Red", "Light Orange",
"Lime", "Sea Green", "Aqua", "Light Blue", Violet}
End Class 'ColorPaletteDialog
Dim moreColorsButton As New Button()
Dim cancelButton As New Button()
Dim selectedColor As Color
Public Sub New(x As Integer, y As Integer)
Size =
New Size(158, 132)
FormBorderStyle = FormBorderStyle.FixedDialog
MinimizeBox =(MaximizeBox <<=(ControlBox <<=
False))
ShowInTaskbar =
False
CenterToScreen()
Location =
New Point(x, y)
BuildPalette()
moreColorsButton.Text = "More colors ..."
moreColorsButton.Size =
New Size(142, 22)
moreColorsButton.Location =
New Point(5, 99)
AddHandler moreColorsButton.Click, AddressOf moreColorsButton_Click
moreColorsButton.FlatStyle = FlatStyle.Popup
Controls.Add(moreColorsButton)
'"invisible" button to cancel at Escape
cancelButton.Size = New Size(5, 5)
cancelButton.Location =
New Point(- 10, - 10)
AddHandler cancelButton.Click, AddressOf cancelButton_Click
Controls.Add(cancelButton)
cancelButton.TabIndex = 0
Me.CancelButton = cancelButton
End Sub 'New
Public ReadOnly Property Color() As Color
Get
Return
selectedColor
End
Get
End
Property
Sub BuildPalette()
Dim pwidth As Byte = 16
Dim pheight As Byte = 16
Dim pdistance As Byte = 2
Dim border As Byte = 5
Dim x As Integer = border
Dim y As Integer = border
Dim toolTip As New ToolTip()
Dim i As Integer
For
i = 0 To max - 1
panel(i) =
New Panel()
panel(i).Height = pwidth
panel(i).Width = pheight
panel(i).Location =
New Point(x, y)
toolTip.SetToolTip(panel(i), colorName(i))
Me.Controls.Add(panel(i))
If x < 7 *(pwidth + pdistance) Then
x += pwidth + pdistance
Else
x = border
y += pheight + pdistance
End If
panel(i).BackColor = color(i)
AddHandler panel(i).MouseEnter, AddressOf OnMouseEnterPanel
AddHandler panel(i).MouseLeave, AddressOf OnMouseLeavePanel
AddHandler panel(i).MouseDown, AddressOf OnMouseDownPanel
AddHandler panel(i).MouseUp, AddressOf OnMouseUpPanel
AddHandler panel(i).Paint, AddressOf OnPanelPaint
Next i
End Sub 'BuildPalette
Sub moreColorsButton_Click(sender As Object, e As System.EventArgs)
Dim colDialog As New ColorDialog()
colDialog.FullOpen =
True
colDialog.ShowDialog()
selectedColor = colDialog.Color
colDialog.Dispose()
Close()
End Sub 'moreColorsButton_Click
Sub cancelButton_Click(sender As Object, e As System.EventArgs)
Close()
End Sub 'cancelButton_Click
Sub OnMouseEnterPanel(sender As Object, e As EventArgs)
DrawPanel(sender, 1)
End Sub 'OnMouseEnterPanel
Sub OnMouseLeavePanel(sender As Object, e As EventArgs)
DrawPanel(sender, 0)
End Sub 'OnMouseLeavePanel
Sub OnMouseDownPanel(sender As Object, e As MouseEventArgs)
DrawPanel(sender, 2)
End Sub 'OnMouseDownPanel
Sub OnMouseUpPanel(sender As Object, e As MouseEventArgs)
Dim panel As Panel = CType(sender, Panel)
selectedColor = panel.BackColor
Close()
End Sub 'OnMouseUpPanel
Sub DrawPanel(sender As Object, state As Byte)
Dim panel As Panel = CType(sender, Panel)
Dim g As Graphics = panel.CreateGraphics()
Dim pen1, pen2 As Pen
If state = 1 Then 'mouse over
pen1 =
New Pen(SystemColors.ControlLightLight)
pen2 =
New Pen(SystemColors.ControlDarkDark)
Else
If state = 2 Then 'clicked
pen1 =
New Pen(SystemColors.ControlDarkDark)
pen2 =
New Pen(SystemColors.ControlLightLight)
'neutral
Else
pen1 = New Pen(SystemColors.ControlDark)
pen2 =
New Pen(SystemColors.ControlDark)
End If
End If
Dim
r As Rectangle = panel.ClientRectangle
Dim p1 As New Point(r.Left, r.Top) 'top left
Dim p2 As New Point(r.Right - 1, r.Top) 'top right
Dim p3 As New Point(r.Left, r.Bottom - 1) 'bottom left
Dim p4 As New Point(r.Right - 1, r.Bottom - 1) 'bottom right
g.DrawLine(pen1, p1, p2)
g.DrawLine(pen1, p1, p3)
g.DrawLine(pen2, p2, p4)
g.DrawLine(pen2, p3, p4)
End Sub 'DrawPanel
Sub OnPanelPaint(sender As [Object], e As PaintEventArgs)
DrawPanel(sender, 0)
End Sub 'OnPanelPaint.

Points of Interest

The little panels show the name of the selected color under the curser inside a tool tip. They also change their appearance, when the mouse hovers over them or clicks them. In order to do this, the Paint method for the panel is overloaded and we draw the borders of the panel ourselves (using System colors), dependant of the state of the mouse.