Introduction
A color picker... isn't there a bunch of those out there already? Yeah, but none of them were really what I needed. There are some cool ones, but
they were either too big, or too limited. Besides, I enjoy the challenge. What I wanted was to be able to easily select a color from a color gradient bar and
adjust the brightness and saturation (HSB). Again, already out there, but I wanted a control with a smaller footprint. I didn't want the control taking up most of my
form area, and I didn't want to have to open a separate dialog every time. So, here is my version.
Controls in Library
- gColorPicker
- gEyeDropper
- gColorComboBox
- gEnumBox
ColorPicker Control Features
- Hue (Color) selection bar
- Saturation adjustment bar
- Brightness adjustment bar
- Alpha (Transparency) adjustment slider
- RGB - Red, Green, and Blue adjustment track bars (optional)
- Predefined color swatches fly-out
- EyeDropper tool to select a color from anywhere on your screen
Events
Public Event ColorPicked(ByVal sender As Object, _
ByVal CurrentColor As Color, ByVal ClosestColorName As String)
This event will fire when the color bar is clicked.
Public Event ColorChanging(ByVal sender As Object, _
ByVal CurrentColor As Color, ByVal ClosestColorName As String)
This event will fire when the color value is changing.
Init
The class Implements ISupportInitialize
.
Then using the code below the ColorChanging
event can be blocked in the Value Property
during the control's initialization.
Private Sub BeginInit() Implements ISupportInitialize.BeginInit
Initializing = True
End Sub
Private Sub EndInit() Implements ISupportInitialize.EndInit
Initializing = False
End Sub
Initialize
Builds the color bars and lays out the control. There are two resources loaded here. First is HideCursor.cur. This is a blank cursor used when the bar
selectors are being adjusted so cursor will disappear. The second is the Lizardsml.jpg to tile behind the color bar to show the alpha
transparency better. It will load a backup for each if, for some reason, these resources are missing.
Control Properties
Here is a list of the primary properties:
Value
The current color selected.
HideRGB
Shows or hides the RGB control box.
FlyOut
Does the fly-out open on MouseOver
or Click
? This property is also available from a context-menu at runtime.
Color Helpers
Special thanks to Guillaume Leparmentier for his great article: Manipulating colors
in .NET - Part 1 [^]. To convert between RGB and HSB,
I used some of his RGB/HSB helper code here, with little modification.
Mouse Events
Track if the cursor is over a bar or over the alpha pointer.
For rectangular areas:
If New Rectangle(ptColor, szColor).Contains(e.Location) Then
.
.
.
End If
For irregular areas (GraphicsPath
):
If GetAlphaPath(sngXAlpha).IsVisible(e.Location) Then
.
.
.
End If
Drawing
Contains the routines to draw the bars and the pointers, invalidate selectors, and paint the control.
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Dim g As Graphics = e.Graphics
g.FillRectangle(New TextureBrush(bmpImg, WrapMode.Tile), ValueDisplay)
g.FillRectangle(New SolidBrush(Color.FromArgb(CInt(nudAlpha.Value), _
_Value)), ValueDisplay)
g.DrawRectangle(Pens.DarkGray, ValueDisplay.Location.X - 3, _
ValueDisplay.Location.Y - 3, ValueDisplay.Width + 5, _
ValueDisplay.Height + 5)
g.FillPath(New SolidBrush(AlphaColor), GetAlphaPath(sngXAlpha))
g.DrawPath(Pens.Blue, GetAlphaPath(sngXAlpha))
g.DrawImage(bmpColorBar, ptColorPaint)
DrawSelector(g, New Rectangle(ptColor, szColor), _
sngXColor, panHueSwatch.BackColor)
Using br As LinearGradientBrush = New LinearGradientBrush _
(New Rectangle(ptSatPaint.X + 3, ptSatPaint.Y + 3, _
szSat.Width, szSat.Height), _
Color.White, CurrColor, LinearGradientMode.Horizontal)
g.FillRectangle(br, New Rectangle( _
ptSatPaint.X + 3, ptSatPaint.Y + 3, szSat.Width, szSat.Height))
g.DrawRectangle(Pens.DarkGray, New Rectangle( _
ptSatPaint.X, ptSatPaint.Y, szSat.Width + 5, szSat.Height + 5))
End Using
DrawSelector(g, New Rectangle(ptSat, szSat), sngXSat, _
HSBtoColor(nudHue.Value, nudSat.Value / 100, 1))
g.DrawImage(bmpBrightBar, ptBrightPaint)
DrawSelector(g, New Rectangle(ptBright, szBright), sngXBright, _
HSBtoColor(0, 0, nudBright.Value / 100))
End Sub
Control Events
Contains the events for the controls on the color picker control.
ColorBox
DrawItem
event to take over drawing the combobox items and adding a color sample to each item.
EyeDropper Events
Update the sample and color value based on the EyeDropper
control. The EyeDropper
has these two events:
Public Event SelectedColorChanging(ByVal sender As Object, _
ByVal CurrColor As Color)
Public Event SelectedColorChanged(ByVal sender As Object, _
ByVal CurrColor As Color)
ColorPickerDesigner
ControlDesigner
that makes the SmartTag. Go here for the designer How-to's: UITypeEditorsDemo[^].
EyeDropper
The EyeDropper
button can actually
be used as a separate control, if you want. Use the dll or add the Class, and add Dropper.cur as an embedded resource.
Clicking the button activates the control and opens the zoom window. It stays active as long as the mouse button remains pressed. Releasing the mouse button will set the selected color.
As the Mouse is moving with the button pressed it is calling the Sub GetScreenShot
.
GetScreenShot
will determine the rectangular area around the mouse position for the screen shot. Then it calls the CopyFromScreen
from the Graphics
object to get the Bitmap
of that part of the screen. Then using the GetPixel
function of the
Bitmap
on the center point to get the Color
of the pixel.
ZoomWindowType
- Sets if the zoom window will show in place or show as a Custom Cursor
that moves with the mouse.
The Custom Cursor
uses techniques from the gCursor[^].
ShowSelectedSwatch
- Sets if the zoom window will show a swatch of the Selected Color
.
Show Zoom Window In Place
Show Zoom Window As Custom Cursor
ZoomLevel
Set the ZoomLevel to change how big the pixels are enlarged in the zoom window.
Sub GetScreenShot()
Dim scrPt As Point = Control.MousePosition
scrPt.X = CInt(scrPt.X - bmpScreenShot.Width / 2)
scrPt.Y = CInt(scrPt.Y - bmpScreenShot.Height / 2)
Using g As Graphics = Graphics.FromImage(bmpScreenShot)
g.CopyFromScreen(scrPt, New Point(0, 0), bmpScreenShot.Size)
End Using
SelectedColor = bmpScreenShot.GetPixel( _
CInt(bmpScreenShot.Size.Width / 2), _
CInt(bmpScreenShot.Size.Height / 2))
Invalidate()
End Sub
gTrackBar RGB Sliders - New in version 1.3
I replaced the Microsoft TrackBars I used for the RGB adjustments with my gTrackBar [^]. Why? It just looks better.
Put the gColorPicker into a DropDown
For an even smaller footprint, you can put the gColorPicker
into a dropdown. Here are a couple of options.
ToolStripDropDownButton
Host the gColorPicker
in a ToolStripDropDownButton
: First declare the gColorPicker
and ToolStripDropDownButton
.
Private WithEvents gcpToolStripForeColor As ColorPickerLib.gColorPicker = _
New ColorPickerLib.gColorPicker
Private ReadOnly ToolStripDropDownButton1 As ToolStripDropDownButton = _
New ToolStripDropDownButton()
Then set it all up in the Form's Load Event.
gcpToolStripForeColor.Value = lblTextSample.ForeColor
gcpToolStripForeColor.BackColor = Color.White
Dim Host1 As ToolStripControlHost = _
New ToolStripControlHost(gcpToolStripForeColor)
Host1.AutoSize = False
Dim dropDown1 As New ToolStripDropDown()
dropDown1.Items.Add(Host1)
ToolStripDropDownButton1.Text = "ForeColor"
ToolStripDropDownButton1.DisplayStyle = _
ToolStripItemDisplayStyle.ImageAndText
ToolStripDropDownButton1.Image = _
MakeColorSquare(gcpToolStripForeColor.Value)
ToolStrip1.Items.Add(ToolStripDropDownButton1)
ToolStripDropDownButton1.DropDown = dropDown1
DropDownContainer
I made a DropDownContainer
to put the ColorPicker
or any control(s) in the
DropDownContainer
[^].
Add this code to make the color box in the DropDownContainer
:
Private Sub ColorPicker1_ColorPicked(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles ColorPicker1.ColorPicked
Dim bm As Bitmap = New Bitmap(30, 20)
Using g As Graphics = Graphics.FromImage(bm)
g.FillRectangle(Brushes.White, 0, 0, 30, 20)
g.FillRectangle(New SolidBrush(ColorPicker1.Value), 0, 0, 30, 20)
DropDownContainer1.GraphicImage = bm.Clone
bm.Dispose()
End Using
DropDownContainer1.CloseDropDown()
End Sub
Replace the MS Color Editor for the Color Property
If you want to use the gColorPicker
instead of the standard one, just reference the ColorPickerLib
and add this Attribute to the property:
<Editor(GetType(gColorPickerDDEditor), GetType(UITypeEditor))> _
For example:
<Editor(GetType(gColorPickerDDEditor), GetType(UITypeEditor))> _
Public Property BorderColor() As Color
Get
Return _borderColor
End Get
Set(ByVal Value As Color)
_borderColor = Value
Invalidate()
End Set
End Property
How this works is fully explained in my UITypeEditor article: UITypeEditorsDemo[^].
gColorComboBox and gEnumBox
These are a couple of additional controls added to the library. They are extensions of the ComboBox
. The gColorComboBox
lists all the
known colors along with a color swatch sample. The gEnumBox
takes three enumerations commonly used when I have been editing colors and adds
a sample example to the dropdown items. Rather than create a whole new project and library, I decided to add them to this one.
DashStyle
HatchStyle
LineJoin
So I did not have to make three separate controls, I added a property that lets you update the ComboBox Items
with the items in the chosen enumeration.
Enum eStyle
DashStyle
HatchStyle
LineJoin
End Enum
Private _enumStyle As eStyle = eStyle.Dashstyle
Public Property EnumStyle() As eStyle
Get
Return _enumStyle
End Get
Set(ByVal Value As eStyle)
_enumStyle = Value
Items.Clear()
If Not DesignMode Then
Select Case Value
Case eStyle.DashStyle
Items.AddRange([Enum].GetNames(GetType(DashStyle)))
Case eStyle.HatchStyle
Items.AddRange([Enum].GetNames(GetType(HatchStyle)))
Case eStyle.LineJoin
Items.AddRange([Enum].GetNames(GetType(LineJoin)))
End Select
End If
End Set
End Property
Then in the DrawItem
event, it draws the Item
according to the current EnumStyle
.
History
- Version 1.0 - October 2008
- Version 1.1 - October 2008
- Moved
RaiseEvent ColorChanging(Me)
out of the Sub UpdateColor
and into the Value
Set Property block
and removed the unnecessary code from the Sub UpdateColor
to catch holes in the ColorChanging Event
.
- Version 1.2 - December 2008
- Updated code to comply with Option Strict turned On
- Fixed small glitch in Initializing the control
- Updated Mouse Events
- Version 1.3 - April 2009
- Added new custom RGB
Trackbar
Sliders
- Version 1.4 - September 2011
- Added
CurrentColor
and ClosestColorName
to ColorPicked
event
- Auto set
Sat
and Bright
to 100 when color is black and Hue is Clicked
- Removed the hardcoded
KnownColor
list and use the new SortColors
function
- Version 1.5 - September 2011
- Added Custom Cursor option to the EyeDropper
- Version 1.6 - September 2011
- Added demonstration of how to add
gColorPicker
to a ToolStrip
- Version 1.7 - October 2011
- Moved the initialization of the color list in the
gColorComboBox
to stop multiple loading of the list
- Added the new
gEnumBox
for easier style formatting
- Added some properties to the
gColorComboBox
to match the gEnumBox
- Version 1.8 - January 2012
- Added
UITypeEditor
so the gColorPicker
can be used in the PropertyGrid