Introduction
Any big framework's handicap is a low number of visual controls. Luckily the most useful are very often present, but sometimes we find some problems with the less common controls. Some days ago, I made a program that translates colors in HTML code. I first used three trackbars to change the red, green, and blue values. Later, I needed to put a more quick and intuitive solution, so I build this ColorPicker control. This control allows to select a color faster than using the previous method. Because I haven't seen a similar control in this site, I decided to post it here. In a recent update, I added a number of new controls. All the available controls are listed below:
ColorPickers (namespace Fuliggine.ColorPickers) |
StableColorPicker |
Is a circular color picker that allows to select a single color. |
SquareColorPicker |
Is a control that, given a base color, shows and allows to select its tones. |
ColorBar |
Is a control that shows and allow to select all base colors derived from an RGB, except white and black. |
FullColorBar |
Is a control that shows and allows to select all base colors derived from an RGB (also white and black). |
ColorViewers (namespace Fuliggine.ColorPickers) |
MonoFrameColor |
Is a control with a frame that shows the selected color. |
DoubleFrameColor |
Is a control with two frames that show the two selected colors. |
ColorGradient |
Is a control that shows all tones of a given color. |
Special Pointers (namespace Fuliggine.ColorPickers) |
HolePointer |
Is the pointer that selects the color in the controls. |
The ColorPicker Controls
For ColorBar
and FullColorBar
controls, I divide the width in sections to allow all the possible combinations of R, G, B. After that, I find the step of color done in every pixel and draw the control line by line...
protected override void OnPaint(PaintEventArgs e)
{
int R=255;
int G=0;
int B=0;
int colorstep=255/ ( this.Width/6 );
int i=0;
for(B=0;B<256;B+=colorstep ,i++)
{
e.Graphics.DrawLine(new Pen(new SolidBrush(
Color.FromArgb(R,G,B)),1),i,0,i,this.Height);
}
B=255;
for(R=255;R>0;R-=colorstep,i++)
{
e.Graphics.DrawLine(new Pen(new SolidBrush(
Color.FromArgb(R,G,B)),1),i,0,i,this.Height);
}
R=0;
for(G=0;G<256;G+=colorstep,i++)
{
e.Graphics.DrawLine(new Pen(new SolidBrush(
Color.FromArgb(R,G,B)),1),i,0,i,this.Height);
}
G=255;
for(B=255;B>0;B-=colorstep,i++)
{
e.Graphics.DrawLine(new Pen(new SolidBrush(
Color.FromArgb(R,G,B)),1),i,0,i,this.Height);
}
B=0;
for(R=0;R<256;R+=colorstep,i++)
{
e.Graphics.DrawLine(new Pen(new SolidBrush(
Color.FromArgb(R,G,B)),1),i,0,i,this.Height);
}
R=255;
B=0;
for(G=255;G>0;G-=colorstep,i++)
{
e.Graphics.DrawLine(new Pen(new SolidBrush(
Color.FromArgb(R,G,B)),1),i,0,i,this.Height);
}
}
A similar way is used in ColorGradient
and SquareColorPicker
, but only the tones of the color are shown there.
protected override void OnPaint(PaintEventArgs e)
{
int ScaleY=255/this.Height;
for ( int y = 0 ; y<this.Height;y++)
{
int r=pColor.R-(y*ScaleY);
if(r<0)
{
r=0;
}
int g=pColor.G-(y*ScaleY);
if(g<0)
{
g=0;
}
int b=pColor.B-(y*ScaleY);
if(b<0)
{
b=0;
}
e.Graphics.DrawLine(new Pen(new SolidBrush(
Color.FromArgb(r,g,b)),1),0,y,this.Width,y);
}
}
The mono and double frame colors are realized by simple panels. The HolePointer
is a simple control that bring itself in the parent bounds when the mouse drags it. Based on its position, controls will decide what the selected color is.
The Color Picker Application
The demo is a nice application, and simple but useful for those who use HTML. The application shows a way to use the StableColorPicker
.
How to Find the RGB Color
I decided to do a round rainbow. The main problem was that in an RGB system, we have three variables, and in a plain, there are only two. So I decided to take the x value as Red, Y value as Green, and the distance from the center as Blue. The circle is inscribed in a square of 255 pixels for each side. The distance from the center is calculated with Pythagoras's Theorem and resized to fit in the range 0-255. So at every point is associated a value between 0 and 255.
How to Paint the Circle
To paint the circle, I have two methods: the first one is to paint all the points on the ray, for each angle; the second one is to paint every point in a circle. The method to use can be selected by the user. The code is shown here:
protected override void OnPaint(PaintEventArgs e)
{
int offsett= 1;
int width=this.ClientRectangle.Width-2;
int height=this.ClientRectangle.Height-2;
int rx= width/2;
int x=10;
int y=10;
int cx=offsett+rx;
double teta=0 ;
e .Graphics.FillRectangle(new SolidBrush(this.BackColor),
this.ClientRectangle);
if ( AnimationRadial==true)
{
for ( teta = 0 ; teta <2*Math.PI; teta=teta + 0.003)
{
for ( double ray = 0 ; ray<rx ;ray= ray+1)
{
x= cx+ Convert.ToInt32(ray* Math.Cos(teta));
y= cx - Convert.ToInt32(ray* Math.Sin(teta));
Rectangle rect= new Rectangle(x,y,1,1);
e.Graphics.FillRectangle(new SolidBrush(
Color.FromArgb(x,y,(int)(ray/rx*255))),rect);
}
}
}
else
{
for ( double ray = 0 ; ray<rx ;ray= ray+1)
{
for ( teta = 0 ; teta <2*Math.PI; teta=teta + 0.003)
{
x= cx+ Convert.ToInt32(ray* Math.Cos(teta));
y= cx - Convert.ToInt32(ray* Math.Sin(teta));
Rectangle rect= new Rectangle(x,y,1,1);
e.Graphics.FillRectangle(new SolidBrush(
Color.FromArgb(x,y,(int)(ray/rx*255))),rect);
}
}
}
}
protected override void OnPaint(PaintEventArgs e)
{
int offsett= 1;
int width=this.ClientRectangle.Width-2;
int height=this.ClientRectangle.Height-2;
int rx= width/2;
int x=10;
int y=10;
int cx=offsett+rx;
double teta=0 ;
e.Graphics.FillRectangle(new SolidBrush(this.BackColor),
this.ClientRectangle);
if ( AnimationRadial==true)
{
for ( teta = 0 ; teta <2*Math.PI; teta=teta + 0.003)
{
for ( double ray = 0 ; ray<rx ;ray= ray+1)
{
x= cx+ Convert.ToInt32(ray* Math.Cos(teta));
y= cx - Convert.ToInt32(ray* Math.Sin(teta));
Rectangle rect= new Rectangle(x,y,1,1);
e.Graphics.FillRectangle(new SolidBrush(
Color.FromArgb(x,y,(int)(ray/rx*255))),rect);
}
}
}
else
{
for ( double ray = 0 ; ray<rx ;ray= ray+1)
{
for ( teta = 0 ; teta <2*Math.PI; teta=teta + 0.003)
{
x= cx+ Convert.ToInt32(ray* Math.Cos(teta));
y= cx - Convert.ToInt32(ray* Math.Sin(teta));
Rectangle rect= new Rectangle(x,y,1,1);
e.Graphics.FillRectangle(new SolidBrush(
Color.FromArgb(x,y,(int)(ray/rx*255))),rect);
}
}
}
}
How to Select a Color
To select a color, I made a special class that can be moved by the user. Every color picture has one of this and the control returns the color under it.
Problems
A big problem is the flicker in repainting. I took the screenshot of the control and put it on a new control derived from PaintBox
. This isn't an elegant solution, but works... I call this new control StableColorPicker
.
Classes
In this release, there is the first version of the control (ColorPicker
) which works fine but isn't very stable, and the second stable version (StableColorPicker
).
Credits
This is only one of the possible solutions. Maybe this isn't the good, but I think that it's simple and fast. For advice, questions, or problems, please contact me.
If you would like to see my other works, please visit my home page: http://zeppaman.altervista.org.