Click here to Skip to main content
15,884,099 members
Articles / Multimedia / GDI+
Tip/Trick

ColorSelector and MenuButton in GIS Applications

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
30 Jun 2015CPOL2 min read 6.8K   119  
A ColorSelector control used in GIS Applications, with a menu button for displaying

Introduction

I am a GIS developer, mainly use ArcEngine, which contains a useful color selector control, as shown below:

But ArcEngine is too big and complicated, so I'd like to build my own color select control, written in pure C#, then it can be used in any C# programs.

Background

The color selector control is used to display and select colors, always used with a button with menu, like this:

so the menu button should also be built.

Basic Requirement

The ColorSelector control is displayed via MenuButton, which contains the following requirements:

  1. Display a rectangle and triangle on a button.
  2. Display the ColorSelector control as a contextmenu when clicked.
  3. Change the filling color of rectangle after user picked a color in ColorSelector.

For the ColorSelector control, these are the requirements:

  1. Drawing the default colors.
  2. Display the input color, output the picked color.
  3. Enhance the color when the mouse hovered.
  4. For the colors not contained in default list, display custom color box for user.

Implementation

MenuButton

MenuButton can be extended from a button, followed by this article, the button with drop down menu can easily be built via GDI+, here are the painting codes:

C#
protected override void OnPaint(PaintEventArgs pevent)
{
    this.Text = "";
    base.OnPaint(pevent);

    //Triangle
    int arrowX = ClientRectangle.Width - 14;
    int arrowY = ClientRectangle.Height / 2 - 1;

    Point[] arrows = new Point[] { new Point(arrowX, arrowY), 
    new Point(arrowX + 7, arrowY), new Point(arrowX + 3, arrowY + 4) };
    pevent.Graphics.FillPolygon(m_TriBrush, arrows);

    //split line
    int linex = ClientRectangle.Width - 18;
    int liney = 2;

    pevent.Graphics.DrawLine(m_LinePen1, linex, liney, linex, 
                             liney + ClientRectangle.Height - 6);
    pevent.Graphics.DrawLine(m_LinePen2, linex + 1, liney, linex + 1, 
                             liney + ClientRectangle.Height - 6);

    //rectangle to show color
    pevent.Graphics.FillRectangle(m_FillBrush, 4, 4, 
                                  linex - 7, liney + ClientRectangle.Height - 11);
    pevent.Graphics.DrawRectangle(m_OutLinePen, 3, 3, 
                                  linex - 6, liney + ClientRectangle.Height - 10);
}

Please pay attention to the triangle and split line, which are drawn at the absolute position, so the width of the MenuButton should not be too small, or there will be an exception.

ColorSelector Control

None of the default controls can be used to build the ColorSelector, and since there are so many colors to display, I decided to paint them directly on a UserControl with GDI+.

First, paint the borders:

C#
//draw borders
g.DrawLine(m_OutlineBorderPen, new Point(0, 239), new Point(219, 239));
g.DrawLine(m_OutlineBorderPen, new Point(219, 0), new Point(219, 239));
g.DrawLine(m_OutlinePen, new Point(1, 1), new Point(1, 238));
g.DrawLine(m_OutlinePen, new Point(1, 1), new Point(217, 1));
g.DrawLine(m_EnhancePen, new Point(218, 2), new Point(218, 238));
g.DrawLine(m_EnhancePen, new Point(1, 238), new Point(218, 238));

Then, the colors:

C#
//draw "no color"
g.DrawRectangle(m_EnhancePen, m_TopRect);
g.DrawString("No Color", m_Font, m_FontBrush, 86, 8);
//draw colors
for (int i = 0; i < ROWCOUNT; i++)
{
    for (int j = 0; j < COLUMNCOUNT; j++)
    {
        ColorUnit cu = m_ColorArray[i, j];
        g.FillRectangle(cu.Brush, new Rectangle(cu.InnerPos, cu.InnerSize));
        g.DrawRectangle(m_EnhancePen, new Rectangle(cu.InnerPos, cu.InnerSize));
    }
}
//draw split lines
g.DrawLine(m_EnhancePen, new Point(6, 212), new Point(213, 212));
g.DrawLine(m_OutlinePen, new Point(6, 213), new Point(213, 213));

//draw "more colors"
g.DrawString("More Colors...", m_Font, m_FontBrush, 75, 220);

Enhance the initial color:

C#
//draw initial color
if (m_InitUnit != null)
{
    EnhanceRectangle(g, m_InitUnit.OutterPos, m_InitUnit.OutterSize.Width, 
                     m_InitUnit.OutterSize.Height, true);
}

When the mouse moved over a color, it should be displayed as hovered:

C#
//draw hover color
if (m_HoverUnit != null)
{
    EnhanceRectangle(g, m_HoverUnit.OutterPos, 
    m_HoverUnit.OutterSize.Width, m_HoverUnit.OutterSize.Height);
}

Here is the code for judging a color to be hovered, in mousemove event:

C#
void ucColorPicker_MouseMove(object sender, MouseEventArgs e)
{
    m_HoverUnit = null;
    //other codes...
 
    //default color selected
    int i = (e.X - 5) / 17, j = (e.Y - 31) / 17;
    if (i >= 0 && i < COLUMNCOUNT && j >= 0 && j < ROWCOUNT)
    {
        m_HoverUnit = m_ColorArray[j, i];
        this.Refresh();
    }
}

The default colors are drawn in fixed size and position, which make it easy to get the right color.

When a color was picked by the user, it should be outputted, here is the custom event for output:

C#
public delegate void ColorSelectedHandler(object sender, Color color);
public event ColorSelectedHandler ColorSelected;

Fires in the click event:

C#
void ucColorPicker_MouseClick(object sender, MouseEventArgs e)
{
   //other codes...
   if (ColorSelected != null)
   {
      ColorSelected(this, SelectedColor);
   }           
}

If the user clicks on the other place, the ColorSelector should be hidden as the contextmenu, so the LostFocus event was used:

C#
this.LostFocus += new EventHandler(FormColorPicker_LostFocus);

void FormColorPicker_LostFocus(object sender, EventArgs e)
{
    this.Hide();
}

The System.Windows.Forms.ColorDialog is used to implement the custom colors, shown when the "More Colors..." was Clicked:

C#
void ucColorPicker_MouseClick(object sender, MouseEventArgs e)
{
    Color SelectedColor = Color.FromArgb(0);
    //other codes...
    else if (m_BottomSelected)
    {
        this.Hide();
        if (m_ColorDlg.ShowDialog() == DialogResult.OK)
        {
            SelectedColor = m_ColorDlg.Color;
            ok = true;
        }
    }
    //other codes...
}

The final result looks like this:

Using the Code

Add reference for GISColorSelector.dll, drag the MenuButton to Form, run the program and the MenuButton will show, click the MenuButton, the ColorSelector displays. The source code and demo are in the TestMenuButton_src.zip.

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)
China China
GIS developer in China, interested in C# programming and geometry algorithms.

Comments and Discussions

 
-- There are no messages in this forum --