65.9K
CodeProject 正在变化。 阅读更多。
Home

渐变颜色选择器 V2

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.57/5 (4投票s)

2021年3月28日

CPOL

2分钟阅读

viewsIcon

7610

downloadIcon

244

修订了早期版本的渐变颜色选择器。

目录

引言 目录

本文是对早期 渐变色拾取器 实现的修订 [^]。修订的动力来自于读者对早期实现的评论。

gradient_color_picker

更改的唯一区域是用户界面组件的定位以及 gradient_PANbutton_PAN 面板的实现。有关详细信息,请参考原始文章。

实现 目录

gradient_PAN 目录

当选择起始颜色或结束颜色时,将调用 fill_gradient_PAN 方法。

        // ***************************************** 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

此方法确保已选择起始颜色和结束颜色。如果是,则该方法执行以下操作

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

gradient_PAN 已附加 PAN_OnPaint 事件处理程序。

        // *********************************************** 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

PAN_OnPaint 事件处理程序非常简单。它所做的就是创建一个 LinearGradientBrush [^] 并使用它来填充 gradient_PAN 客户端矩形。

在此修订版中,gradient_PAN 的左侧与 start_color_BUT 的水平中心对齐,gradient_PAN 的右侧与 end_color_BUT 的水平中心对齐。颜色数量标签和数字上下控件已移至起始颜色按钮和结束颜色按钮的中间。

gradient_color_picker

button_PAN 目录

当单击 生成 按钮时,将渲染工具 GUI 的其余部分。在大多数情况下,这需要使各种对象可见。但是,生成 button_PAN 面板要复杂一些。

        // ******************************************* 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

fill_button_PAN 的主要变化是消除了对 gradient_PAN 内容的依赖来确定 button_PAN 中按钮的背景颜色。为了实现这一点,将调用 get_linear_gradient_colors 方法来填充一个颜色列表,该列表的成员将被分配给每个按钮作为其背景颜色。

        // ******************************** get_linear_gradient_colors

        // See https://codeproject.org.cn/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

引入 MinMax 方法是为了避免一遍又一遍地重复相同的逻辑。

        // **************************************************** 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

在此修订版中,colors 列表和 get_linear_gradient_colors 取代了 generate_back_color

致谢 目录

读者评论的作者是

  • steve-redTrans
  • BillWoodruff

我感谢他们提出的评论,这些评论促成了这篇文章的撰写。

参考文献 目录

结论 目录

本文修订了一个工具,该工具能够让开发人员从线性颜色渐变中拾取颜色。

开发环境 目录

渐变色拾取器是在以下环境中开发的

Microsoft Windows 7 专业版 SP 1
Microsoft Visual Studio 2008 专业版 SP1
Microsoft Visual C# 2008
Microsoft .Net Framework Version 3.5 SP1

历史 目录

05/05/2020 原文
05/28/2021 修订版文章
© . All rights reserved.