Click here to Skip to main content
Click here to Skip to main content

Generic Picker Dropdown Control

, 12 Dec 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
A flexible easily overridable combo-box-alike control for choosing from a 2D array of options

Introduction

This article was inspired by Chris Maunder's Office 97 style Colour Picker control. A couple of years ago, I modified it greatly to pick from a palette of colours in my software. Rather than creating my own palette, I used the definitions that Autocad does in DXF files. 0 = black, 1 = white, 2 red, etc. More recently, I needed to add some drawing facilities. Once I added a couple of patterns, I wanted to add the rest. Which makes for a bust 60odd drop down list. Similarly, I wanted drop downs for line width and line styles. 

So I went back to Chris' article, stole/re-used the parts dealing with the popup window, and made the rest. As I knew, I would be making a variety of related controls, I made some member functions pure virtual, and implemented the specific functionality in several inheriting classes.

Lastly, the example project, and most of the pre-built pickers use GDI+. That's not at all related to the core idea - but it was the raison d'etre (sultana of summer, from the French) of the project.

The Pre-built Pickers 

Colour Picker

This is the original one I implemented, and most closely modelled on Chris' implementation.

Line Style

Line Width

Hatch Style

How to Use a Generic Picker Control in Your Own Code.

This is hopefully pretty simple! I'll be using the Line Style Picker as my example. First, add a button to your dialog, and give it an ID number. The text is irrelevant, but nice for editing the dialog later.

Next, include the header file and member variable to your dialog box:

#include "DrawingPickers.h"
...
class CGenericPickerDemoDlg : public CDialog
{
...
	CPickerLineStyle	m_LineStyle;
...
};

Next, subclass the control in your OnInitDialog dialog member function. I also like to initialise the current item. Feel free to use DDX_Control in the DoDataExchange if you wish - but I rarely do.

BOOL CGenericPickerDemoDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
...
	m_LineStyle.SubclassDlgItem (IDC_LINESTYLE, this);
	m_LineStyle.SetStyle (Gdiplus::DashStyleSolid);
...
	return TRUE;  // return TRUE  unless you set the focus to a control
}

To handle changes in selection, you should handle the CBN_SELCHANGE notification. Chris' control used a custom message, but I wanted to be lazy and be able to use ON_CBN_SELCHANGE macro for my code.

BEGIN_MESSAGE_MAP(CGenericPickerDemoDlg, CDialog)
...
	ON_CBN_SELCHANGE(IDC_LINESTYLE, OnPickerChanged)
...
END_MESSAGE_MAP()

Lastly, you need to do something with the selection. In my demo program, I draw a circle with the various styles. As this is not a GDI+ tutorial, I'll skip over that part!

Making Your Own Picker

There are a few pure functions in CGenericPicker you need to override. Here they are:

virtual int GetColumns () const = 0;
virtual int GetRows () const = 0;

virtual void MeasureSubItem(CSize &mis) = 0;

virtual void DrawSubItem(const DrawItemSubStruct &dis) = 0;

virtual BOOL ShowDefaultItem () const = 0;

virtual BOOL IsCellValid (int nCol, int nRow) const { return TRUE; }

I'll show the CPickerLineWidth's implementation as an example.

GetColumns & GetRows

int	CPickerLineWidth::GetColumns () const		{ return 2;	}
int	CPickerLineWidth::GetRows () const		{ return 10;	}

Hopefully these two overridables are fairly self-explanatory! How many boxes wide and high is the 2D drop down...

MeasureSubItem

void CPickerLineWidth::MeasureSubItem(CSize &mis)
{
	mis.cx /= 2;
	mis.cy = 12;
}

MeasureSubItem is called once. The CSize structure is initialised to the same size as the button you added to your dialog. This makes it easy to match the width of the drop down to the width of the parent control. As I have two columns, and neither need to be a specific width, I just split the width between them. For other controls (like colour, or hatch style, this is made to be a fixed size.

DrawSubItem

void CPickerLineWidth::DrawSubItem(const DrawItemSubStruct &dis)
{
	CRect rc (dis.rcItem);
	Graphics graphics (*dis.pDC);
	
	Color colour;
	colour.SetFromCOLORREF(dis.bSelected ? GetSysColor (COLOR_BTNTEXT) : 
					GetSysColor (COLOR_BTNSHADOW));
	
	float fWidth = dis.nRow + float(10 * dis.nColumn);
	fWidth /= 2.0f;
	Pen pen (colour, fWidth);
	
	graphics.DrawLine (&pen, rc.left, rc.top + 6, rc.right, rc.top + 6);
}

DrawSubItem does the heavy lifting of the control. It is used for drawing the button, and for drawing each cell. The DrawItemSubStruct structure has the CDC, drawing rectangle, current column and row, and whether it should be drawn as selected.

The selected option is used to choose between drawing in dark grey or black in my controls. Feel free to be fancier.

ShowDefaultItem

BOOL CPickerLineWidth::ShowDefaultItem () const { return FALSE; }

This isn't really implemented by me - Chris' control uses it. This lets the inheriting controls tell the CGenericPicker class know whether to leave room for a default item. This will be drawn with a column and row of -1.

Acknowledgements

History

  • 1.0 Initial release 

License

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

Share

About the Author

Iain Clarke, Warrior Programmer
Software Developer (Senior)
Sweden Sweden
I have now moved to Sweden for love, and recently married a lovely Swede.
 

-----------------
I started programming on BBC micros (6502) when I was six and never quite stopped even while I was supposed to be studying physics and uni.
 
I've been working for ~13 years writing software for machine control and data analysis. I now work on financial transaction transformation software, for a Software company in Gamlastan, Stockholm.
Look at my articles to see my excellent coding skills. I'm modest too!

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermanoj kumar choubey18-Feb-12 0:58 
QuestionProgrammatically select item? Pinmemberbolivar12316-Feb-10 11:37 
AnswerRe: Programmatically select item? PinmemberIain Clarke, Warrior Programmer7-Jul-10 22:15 
GeneralExcellent Pinmemberbolivar12312-Feb-10 9:34 
GeneralRe: Excellent PinmemberIain Clarke, Warrior Programmer12-Feb-10 12:29 
GeneralGood stuff, Iain PinmvpRajesh R Subramanian11-Oct-09 6:39 
GeneralRe: Good stuff, Iain PinmvpIain Clarke, Warrior Programmer11-Oct-09 6:52 
QuestionAnyone knows how to do this in C#? Pinmembersoft2buy16-Aug-09 8:30 
AnswerRe: Anyone knows how to do this in C#? PinmvpIain Clarke16-Aug-09 21:50 
GeneralRe: Anyone knows how to do this in C#? Pinmembersoft2buy17-Aug-09 5:36 
GeneralThanks for the article. Pinmember Randor 17-Dec-08 3:06 
GeneralRe: Thanks for the article. PinmvpIain Clarke8-Jan-09 0:51 
GeneralMy vote of 2 PinmemberPatLeCat15-Dec-08 1:10 
GeneralRe: My vote of 2 PinmemberIain Clarke15-Dec-08 2:02 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150129.1 | Last Updated 12 Dec 2008
Article Copyright 2008 by Iain Clarke, Warrior Programmer
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid