欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

渐变颜色选择器

程序员文章站 2024-02-05 23:16:46
...

目录

介绍 

用户界面 

实现

gradient_PAN 

button_PAN 

参考文献 

结论 

开发环境 


介绍 

我不确定需要多少次才能生成一种颜色数组,该颜色数组是两种或多种颜色的线性渐变。当为我的网站的COVID-19部分构建动画图形时,我需要生成许多比例。例如:

渐变颜色选择器

随着任务的繁重,我决定开发一种辅助工具。结果是渐变颜色选择器。

渐变颜色选择器

用户界面 

来自* [ ^ ]

轴向颜色渐变(有时也称为线性颜色渐变)由两个点指定,每个点都有一种颜色。使用线性插值计算通过这些点的直线上的颜色。

我想要一个可以为我提供从线性颜色渐变派生的颜色列表的工具。颜色列表将放置在剪贴板中。该工具需要提供以下功能。

  1. 接受两种颜色,然后用线性颜色渐变填充面板(gradient_PAN);接受要从线性颜色渐变中提取的颜色数量。最小颜色数是3(无需使用少于三种颜色的工具);颜色的最大数量为20(受工具客户区大小的限制)。渐变颜色选择器
  2. 当用户单击Generate,该工具将绘制彩色按钮,这些按钮的颜色与关联的线性渐变的颜色相同(即,线性渐变在按钮正上方的颜色)。渐变颜色选择器
  3. 现在向用户显示将颜色值捕获到剪贴板的选项。这些包括:
    1. 用户可以选择将用于剪贴板条目的颜色格式。默认格式为RGB十六进制。
    2. 通过单击任何单独的颜色按钮,该按钮的颜色将复制到剪贴板。两个末端按钮具有原始指定颜色的颜色。如果在示例中单击第六个彩色按钮,则复制到剪贴板的值是:

      'FF6666'
    3. 通过单击从左复制到右,剪贴板从左到右填充了所有彩色按钮颜色的逗号分隔列表。例如,复制到剪贴板的值是:

      '#FFBBBB''FFA7A7''FF9797''FF8787''FF7777'
      'FF6666''FF5656''FF4545 ''FF3535''FF2525''FF1414''FF0000'
    4. 通过单击从右到左复制,剪贴板从右到左填充了所有彩色按钮的颜色的逗号分隔列表。例如,复制到剪贴板的值是:

      'FF0000''FF1414''FF2525''FF3535''FF4545''FF5656'
      'FF6666''FF7777 ''FF8787''FF9797''FFA7A7''FFBBBB'
  4. 如果用户单击重置,则用户返回到步骤1否则,如果用户单击Exit,用户返回步骤1。则应用程序退出。

实现

与任何事件驱动的应用程序一样,初始化主要花费在建立图形用户界面上。对于渐变颜色选择器(Gradient Color Picker),实际上只有两个感兴趣的组件:gradient_PANbutton_PAN面板。

gradient_PAN 

选择开始或结束颜色时,将调用fill_gradient_PAN方法。此方法可确保已访问开始和结束颜色按钮,并且已选择开始和结束颜色。如果是这样,则该方法执行以下操作:

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

gradient_PANPAN_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客户矩形。

button_PAN 

单击生成按钮后,将呈现工具GUI的剩余部分。在大多数情况下,这需要使各种对象可见。但是,生成button_PAN面板要稍微复杂一些。

// ******************************************* fill_button_PAN

bool fill_button_PAN ( )
    {
    int     right_most = 0;
    int     spacing = 0;
    int     top = 2;
    Point   UL = new Point ( 0, 0 ) ;

                                // 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 = ( gradient_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 );

        right_most = button.Location.X + button.Size.Width;

        buttons.Add ( button );
        }
                                // the spacing may not be
                                // large enough to cause the
                                // buttons to completely fill
                                // the button panel to the
                                // right; here we correct the
                                // inter-button spacing;
                                // EPSILON is currently 3
    if ( right_most < ( gradient_PAN.Size.Width - EPSILON ) )
        {
        int pixels = 1;
        int start = 0;
                                // start is expected to be
                                // greater than zero
        start = buttons.Count -
                ( gradient_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;
            }
        }
                                // set the button BackColor;
                                // copy the button from the
                                // buttons List to the
                                // button_PAN
    for ( int i = 0; ( i < buttons.Count ); i++ )
        {
        Button  button = buttons [ i ];
                                // color the button based upon
                                // its current location in the
                                // buttons panel
        if ( i == 0 )
            {
            button.BackColor = start_color;
            }
        else if ( i == ( number_of_colors - 1 ) )
            {
            button.BackColor = end_color;
            }
        else
            {
            generate_back_color ( ref button );
            }
        button.UseVisualStyleBackColor = false;

                                // place button in button_PAN
        button_PAN.Controls.Add ( button );
        }

    button_PAN.Visible = true;

    reset_BUT.Visible = true;

    initialize_miscellaneous_controls ( );

    return ( true );

    } // fill_button_PAN

fill_button_PAN执行以下任务:

  1. 由于应用程序可能会执行多次,因此有必要删除每个按钮上附加的所有事件处理程序。此外,所有按钮均已从button_PAN中删除,所有按钮均已从按钮列表中删除。
  2. 计算初始间隔。请注意,由于舍入误差,计算出的值可能不是按钮之间的最终间距。
  3. 这些按钮是沿着button_PAN面板创建并隔开的,从而跟踪最右边的按钮右侧的位置。
  4. 校正了按钮之间的间距,以使按钮沿button_PAN等距分布。需要执行此步骤,以确保按钮颜色准确地描绘了gradient_PAN的颜色。
  5. 至此,按钮数据已存储在按钮列表中。现在将按钮放入button_PAN。因为最终位置是已知的,所以调用generate_back_color方法最终为每个按钮分配一个BackColor
  6. 最后,使控件的平衡可见。

generate_back_color方法首先计算在gradient_PAN的垂直中心的点,在所述按钮水平居中button_PAN。该点在工具的客户矩形坐标中定义。

渐变颜色选择器

在调用Win32 get_pixel_color_at_location方法之前,必须将点转换为屏幕坐标。

// *************************************** generate_back_color

bool generate_back_color ( ref Button   button )
    {
    Point   point;
    Point   screen_point;


    point = new Point (
                ( ( button_PAN.Location.X +
                    button.Location.X ) +
                  ( button.Size.Width / 2 ) ),
                ( gradient_PAN.Location.Y +
                  ( gradient_PAN.Size.Height / 2 ) ) );
    screen_point = PointToScreen ( point );
    button.BackColor =
        Win32API.get_pixel_color_at_location ( screen_point );

    return ( true );

    } // generate_back_color

Win32get_pixel_color_at_location方法对一个一像素的位图使用GetPixel。将位于指定位置的像素(BitBlt [ ^ ])复制到screen_pixel位图。这带来了四个好处:该方法在多监视器环境中使用时不会引发异常;它比GetPixel更快;使用的位图只有一个像素高和一个宽;并且位图在此方法中是本地的。get_pixel_color_at_location方法采用以下形式:

// **************************************************** BitBlt

[ DllImport ( "gdi32.dll",
              EntryPoint = "BitBlt" ) ]
public static extern bool BitBlt ( IntPtr hdcDest,
                                   int    nXDest,
                                   int    nYDest,
                                   int    nWidth,
                                   int    nHeight,
                                   IntPtr hdcSrc,
                                   int    nXSrc,
                                   int    nYSrc,
                                   int    dwRop );
:
:
// ******************************* get_pixel_color_at_location

public static Color get_pixel_color_at_location (
                                      Point screen_location )
    {
    Color   color;
    Bitmap  screen_pixel = new Bitmap (
                                1,
                                1,
                                PixelFormat.Format32bppArgb );

    using ( Graphics destination = Graphics.FromImage (
                                            screen_pixel ) )
        {
        using ( Graphics source = Graphics.FromHwnd (
                                           IntPtr.Zero ) )
            {
            IntPtr source_DC = source.GetHdc ( );
            IntPtr destination_DC = destination.GetHdc ( );

            BitBlt ( destination_DC,
                     0,
                     0,
                     1,
                     1,
                     source_DC,
                     screen_location.X,
                     screen_location.Y,
                     ( int ) CopyPixelOperation.SourceCopy );
            }
        }

    color = screen_pixel.GetPixel ( 0, 0 );
    screen_pixel.Dispose ( );

    return ( color );
    }

} // class Win32API

参考文献 

结论 

本文介绍了一种工具,该工具为开发人员提供了从线性颜色渐变中选择颜色的功能。

开发环境 

渐变颜色选择器是在以下环境中开发的:

Microsoft Windows 7专业版SP 1

Microsoft Visual Studio专业版2008 Professional SP1

Microsoft Visual C2008

Microsoft .Net Framework版本3.5 SP1