Gradient Color Picker V2






3.57/5 (4 votes)
Revises an earlier implementation of the Gradient Color Picker
Table of Contents
The symbol returns the reader to the top of the Table of Contents.
Introduction
This article revises an earlier implementation of the Gradient Color Picker [^]. The incentive for the revision were reader comments regarding the earlier implementation.
The only areas of change were in the positioning of the user interface components and the implementation of the gradient_PAN and the button_PAN panels. The original article should be referenced for details.
Implementation
gradient_PAN
When either the start or end color is chosen, the fill_gradient_PAN method is invoked.
// ***************************************** fill_gradient_PAN
bool fill_gradient_PAN ( )
{
if ( have_end_color && have_start_color )
{
gradient_PAN.Visible = true;
gradient_PAN.Invalidate ( );
number_of_colors_LAB.Visible = true;
number_of_colors_NUD.Value = number_of_colors;
number_of_colors_NUD.Visible = true;
generate_BUT.Visible = true;
}
return ( true );
} // fill_gradient_PAN
This method insures that both the start and end colors have been chosen. If so, the method executes the following:
gradient_PAN.Visible = true;
gradient_PAN.Invalidate ( );
The gradient_PAN has the PAN_OnPaint event handler attached.
// *********************************************** PAN_OnPaint
void PAN_OnPaint ( object sender,
PaintEventArgs e )
{
base.OnPaint ( e );
e.Graphics.FillRectangle (
new LinearGradientBrush (
gradient_PAN.ClientRectangle,
start_color,
end_color,
0.0F ),
gradient_PAN.ClientRectangle );
} // PAN_OnPaint
The PAN_OnPaint event hander is very simple. All it does is create a LinearGradientBrush [^] and uses it to fill the gradient_PAN client rectangle.
In this revision the left side of the gradient_PAN is aligned horizontally with the horizontal center of the start_color_BUT and the right side of the gradient_PAN is aligned horizontally with the horizontal center of the end_color_BUT. The number of colors label and the numeric up/down control have been moved to midway between the start- and end-color buttons.
button_PAN
When the Generate button is clicked, the balance of the tool's GUI is rendered. In most cases this entails making various objects visible. However, generating the button_PAN panel is somewhat more complex.
// ******************************************* fill_button_PAN
bool fill_button_PAN ( )
{
int right_most = 0;
int spacing = 0;
int top = 2;
// empty and regenerate the
// colors list
colors.Clear ( );
colors = get_linear_gradient_colors ( start_color,
end_color,
number_of_colors );
// remove existing event
// handlers from buttons in
// the button_PAN
foreach ( Control control in button_PAN.Controls )
{
if ( control is Button )
{
control.Click -= new EventHandler (
gradient_BUT_Click );
}
}
// remove any existing buttons
// from the button_PAN
button_PAN.Controls.Clear ( );
// clear the buttons list
buttons.Clear ( );
// compute initial spacing
// between buttons
spacing = ( button_PAN.Size.Width -
( BUTTON_WIDTH * number_of_colors ) ) /
( number_of_colors - 1 );
// create gradient buttons and
// add them to buttons list
for ( int i = 0; ( i < number_of_colors ); i++ )
{
Button button = new Button ( );
int left = ( i * ( spacing + BUTTON_WIDTH ) );
// want no borders
button.FlatStyle = FlatStyle.Popup;
button.Location = new Point ( left, top );
button.Size = BUTTON_SIZE;
button.Click += new EventHandler (
gradient_BUT_Click );
// save the position of the
// right side of the button
right_most = button.Location.X + button.Size.Width;
button.BackColor = colors [ i ];
button.UseVisualStyleBackColor = false;
buttons.Add ( button );
}
// the spacing may not be
// large enough to cause the
// buttons to completely fill
// the button panel; here we
// correct the inter-button
// spacing; EPSILON is
// currently 3
if ( right_most < ( button_PAN.Size.Width - EPSILON ) )
{
int pixels = 1;
int start = 0;
// start is expected to be
// greater than zero
start = buttons.Count -
( button_PAN.Size.Width - right_most );
for ( int i = start; ( i < buttons.Count ); i++ )
{
Point location = buttons [ i ].Location;
location.X += pixels++;
buttons [ i ].Location = location;
}
}
// copy the button from the
// buttons List to the
// button_PAN
for ( int i = 0; ( i < buttons.Count ); i++ )
{
Button button = buttons [ i ];
// place button in button_PAN
button_PAN.Controls.Add ( button );
}
button_PAN.Visible = true;
reset_BUT.Visible = true;
copy_format_GB.Visible = true;
ascending_PB.Visible = true;
copy_left_to_right_BUT.Visible = true;
descending_PB.Visible = true;
copy_right_to_left_BUT.Visible = true;
return ( true );
} // fill_button_PAN
The major change in fill_button_PAN is the elimination of the dependency on the contents of the gradient_PAN to determine the background color of the buttons in the button_PAN. To achieve this, the get_linear_gradient_colors method is invoked to fill a list of colors whose members will be assigned to each button as its background color.
// ******************************** get_linear_gradient_colors
// See https://www.codeproject.com/Articles/5267129/
// Gradient-Color-Picker Bill Woodward comment modified
List < Color > get_linear_gradient_colors (
Color start_color,
Color end_color,
int number_of_colors )
{
List < Color > list = new List < Color > ( 0 );
float count = ( float ) number_of_colors - 1.0F;
float start_R = ( float ) start_color.R;
float difference_R = ( start_R -
( float ) end_color.R ) /
count;
float start_G = ( float ) start_color.G;
float difference_G = ( start_G -
( float ) end_color.G ) /
count;
float start_B = ( float ) start_color.B;
float difference_B = ( start_B -
( float ) end_color.B ) /
count;
for ( int i = 0; ( i < number_of_colors ); i++ )
{
int B = MinMax ( start_B, difference_B, ( float ) i );
int G = MinMax ( start_G, difference_G, ( float ) i );
int R = MinMax ( start_R, difference_R, ( float ) i );
list.Add ( Color.FromArgb ( R, G, B ) );
}
return ( list );
} // get_linear_gradient_colors
The method MinMax was introduced to avoid repeating the same logic over and over again.
// **************************************************** MinMax
int MinMax ( float start,
float difference,
float i )
{
int result = ( int ) ( start - ( i * difference ) + 0.5F );
return ( Math.Max ( 0, Math.Min ( 255, result ) ) );
} // MinMax
In this revision, the colors list and get_linear_gradient_colors replace generate_back_color.
Acknowlegments
The authors of the readers comments are:
- steve-redTrans
- BillWoodruff
I thank both for their comments that caused this article to be written.
References
- LinearGradientBrush [^]
- Wikipedia [^]:
Conclusion
This article has revised a tool that provides developers with the ability to pick colors from a linear color gradient.
Development Environment
The Gradient Color Picker was developed in the following environment:
Microsoft Windows 7 Professional SP 1 |
Microsoft Visual Studio 2008 Professional SP1 |
Microsoft Visual C# 2008 |
Microsoft .Net Framework Version 3.5 SP1 |
History
05/05/2020 | Original article |
05/28/2021 | Revised article |