Click here to Skip to main content
15,867,328 members
Articles / Multimedia / GDI+

Gradient Color Picker V2

Rate me:
Please Sign up or sign in to vote.
3.57/5 (4 votes)
28 Mar 2021CPOL2 min read 6.3K   204   5   2
Revises an earlier implementation of the Gradient Color Picker
Gradient Color Picker V2 revises the earlier implementation by revising the user interface and eliminating a need to determine the color of a pixel at a specific screen location.

Table of Contents

Introduction Table of Contents

This article revises an earlier implementation of the Gradient Color Picker [^]. The incentive for the revision were reader comments regarding the earlier implementation.

gradient_color_picker

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 Table of Contents

gradient_PAN Table of Contents

When either the start or end color is chosen, the fill_gradient_PAN method is invoked.

C#
// ***************************************** 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:

C#
gradient_PAN.Visible = true;
gradient_PAN.Invalidate ( );

The gradient_PAN has the PAN_OnPaint event handler attached.

C#
// *********************************************** 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.

gradient_color_picker

button_PAN Table of Contents

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.

C#
// ******************************************* 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.

C#
// ******************************** 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.

C#
// **************************************************** 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 Table of Contents

The authors of the readers comments are:

  • steve-redTrans
  • BillWoodruff

I thank both for their comments that caused this article to be written.

References Table of Contents

Conclusion Table of Contents

This article has revised a tool that provides developers with the ability to pick colors from a linear color gradient.

Development Environment Table of Contents

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 Table of Contents

05/05/2020 Original article
05/28/2021 Revised article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
In 1964, I was in the US Coast Guard when I wrote my first program. It was written in RPG (note no suffixing numbers). Programs and data were entered using punched cards. Turnaround was about 3 hours. So much for the "good old days!"

In 1970, when assigned to Washington DC, I started my MS in Mechanical Engineering. I specialized in Transportation. Untold hours in statistical theory and practice were required, forcing me to use the university computer and learn the FORTRAN language, still using punched cards!

In 1973, I was employed by the Norfolk VA Police Department as a crime analyst for the High Intensity Target program. There, I was still using punched cards!

In 1973, I joined Computer Sciences Corporation (CSC). There, for the first time, I was introduced to a terminal with the ability to edit, compile, link, and test my programs on-line. CSC also gave me the opportunity to discuss technical issues with some of the brightest minds I've encountered during my career.

In 1975, I moved to San Diego to head up an IR&D project, BIODAB. I returned to school (UCSD) and took up Software Engineering at the graduate level. After BIODAB, I headed up a team that fixed a stalled project. I then headed up one of the two most satisfying projects of my career, the Automated Flight Operations Center at Ft. Irwin, CA.

I left Anteon Corporation (the successor to CSC on a major contract) and moved to Pensacola, FL. For a small company I built their firewall, given free to the company's customers. An opportunity to build an air traffic controller trainer arose. This was the other most satisfying project of my career.

Today, I consider myself capable.

Comments and Discussions

 
GeneralMessage Closed Pin
30-Mar-21 0:31
Member 1512661130-Mar-21 0:31 
QuestionTable of content Pin
Kenneth Haugland29-Mar-21 1:44
mvaKenneth Haugland29-Mar-21 1:44 
GeneralMy vote of 5 Pin
BillWoodruff28-Mar-21 18:56
professionalBillWoodruff28-Mar-21 18:56 
Good work !

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.