渐变颜色选择器

目录

介绍 

用户界面 

实现

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值