Office 97 style Colour Picker control

Environment: VC4, VC5, VC6, Win9x, WinNT

This sample was contributed by Chris Maunder, and extended by Alexander Bischofberger.

Colour Picker image Download source files (13 Kb) or sample project (41 Kb).

Latest updates here. (version 1.3)

In an effort to have the latest and greatest wizz-bang features in my programs I unashamedly ripped of the colour picker from Office 97.

Initially I tried to modify an owner drawn combo box and combine that with a multicolumn combobox, but current multicolumn combo boxes are really just a single column with dividing lines drawn in. I then decided to write the whole thing from scratch based on a button, since it would at least give me a BN_CLICKED notification to get things started.

The colour picker is in two parts: an owner drawn button that reflects the currently selected colour, and a popup colour chooser window to select this colour. When the user clicks on the button the popup window appears and all mouse messages are captured until the left mouse button is clicked, or until the Enter or Escape keys are pressed. The popup window can be navigated using the mouse or the keyboard and includes tooltips explaining what each colour is.

The control can be incorporated into a project like any other Cbutton derived control. Either Create the control manually, subclass an existing CButton or DDX_control it. The control also comes with a DDX_ColourPicker routine to get/set the colour of the control using a variable of type COLORREF.

The Colour Picker is contained in the class CColourPicker. It uses the class CColourPopup for the popup window. These classes are contained in the file colour_picker_src.zip, and a sample project is contained in colour_picker_demo.zip.

CColourPicker only has the following public member functions:

		void     SetColour(COLORREF crColour);
		COLORREF GetColour();

		void     SetDefaultText(LPCTSTR szDefaultText);
		void     SetCustomText(LPCTSTR szCustomText);

		void     SetSelectionMode(UINT nMode); // Either CP_MODE_TEXT or CP_MODE_BK
		UINT     GetSelectionMode();

		void     SetBkColour(COLORREF crColourBk);
		COLORREF GetBkColour();
    
		void     SetTextColour(COLORREF crColourText);
		COLORREF GetTextColour();

SetDefaultText allows you to set the text that will appear in the "Default" area of the colour chooser. If you pass NULL, then the Default area will not be available to the user. If this area is availble and the user selects it, the value CLR_DEFAULT will be returned.

SetCustomText allows you to set the text that will appear in the "Custom" area of the colour chooser. If you pass NULL, then the Custom area will not be available to the user. The Custom area allows the user to select a custom colour using the standard windows colour selection dialog.

You can choose whether the colour chosen using the dropdown colour chooser will affect the text or the background colour using the function SetSelectionMode(int nMode). Possible values for nMode are CP_MODE_TEXT to make colour changes affect the text colour, and CP_MODE_BK to make changes affect the background (default).

SetColour, GetColour and the the DDX-function will set and get the colour according to the current selection mode. To access the text colour and the background colour directly use the Set/GetTextColour and Set/GetBkColour functions.

There are also a number of user messages that may be handled to get more information from the control. These are:
 

Message Description
CPN_SELCHANGE Colour Picker Selection change
CPN_DROPDOWN Colour Picker drop down
CPN_CLOSEUP Colour Picker close up
CPN_SELENDOK Colour Picker end OK
CPN_SELENDCANCEL Colour Picker end (cancelled)

These messages can be handled using ON_MESSAGE(< MESSAGE>, MessageFn) in you message map entries, where MessageFn is of the form


    afx_msg LONG MessageFn(UINT lParam, LONG wParam);

The demo program gives an example of how to do this.




New in Version 1.1

The following changes have been made by Alexander Bischofberger.

The original version did not display a text inside the combo box. The current version now displays the button text (as set in the dialog resource, or via SetWindowText). You can choose whether the colour chosen using the dropdown colour chooser will affect the text or the background colour using the new member function SetSelectionMode:

		#define CP_MODE_TEXT 1		// Colour selection affects text colour
		#define CP_MODE_BK   2		// Colour selection affects background colour (default)

		void     SetSelectionMode(UINT nMode);
		UINT     GetSelectionMode();
Two new member functions have been introduced to set the text colour and the background colour directly:
		void     SetBkColour(COLORREF crColourBk);
		COLORREF GetBkColour();
    
		void     SetTextColour(COLORREF crColourText);
		COLORREF GetTextColour();

SetColour, GetColour and the the DDX-function will set and get the colour according to the current selection mode.

Some minor changes were made in the drawing routine (now faster and able to show a pressed combo box button), the messaging (CPN_SELCHANGE now sent to the parent).

The following changes have been made by Chris Maunder.

The button now stays pressed while colour choosing is in progress, and the initial colour sent to the drop down colour chooser is highlighted as in Office 97. Oh - and a line now separates the Custom Text area from the colours. weee!

Palette support is now included so things don't look so bad in 256 colours.

See the updated sample how to use the new functionality.

New in Version 1.2

The following changes have been made by Chris Maunder.

The picker now looks a little more like the office 97 version, although it does not as yet support the "cool" look. Any number of colours can now be used in the picker (although these are still hardwired in).

Two new functions were added:

		void SetDefaultText(LPCTSTR szDefaultText);
		void SetCustomText(LPCTSTR szCustomText);

These specify the text (if any) that will appear in the "Default" selection area and the "Custom colour" selection area. See main section of this doc for details.

New in Version 1.21

Minor bug fix when losing focus to another application. Fix suggested by Paul Wilkerson.

New in Version 1.3

Colour cells now drawn with thin border (thanks to Geir Arne Trillhus). If cancel is hit in the custom colour picker popup, a CPN_SELENDOK is no longer sent. Also compiles clean under VC6

Updated 9 January 1999



Comments

  • Fansatic

    Posted by Ajay Vijay on 11/20/2004 06:00am

    Great and amazing work!

    Reply
  • How can I using ColorPicker in my Toolbar?

    Posted by Legacy on 01/09/2004 12:00am

    Originally posted by: Eugene Kim

    I tried , and using Create function of CButton.
    It looks like to work , but always in disabled mode.

    I have no idea how to change or, I think in creation period, something needed or some option to include ..

    Anyway, color Picker does not work . plz. help me.


    Code.. Like this. !!!

    m_ColorText.Create(_T(""), WS_CHILD|WS_VISIBLE, Colorrect, this, ID_FONT_COLOR);

    Reply
  • cannot open file "mfc42u.lib"

    Posted by Legacy on 05/11/2003 12:00am

    Originally posted by: arnold

    complie error is "cannot open file "mfc42u.lib""

    Reply
  • doesn't show right color

    Posted by Legacy on 05/25/2001 12:00am

    Originally posted by: new user

    If you click on ColorPicker, it doesn't show the the selected color of ColorPicker. Instead it just displays all colors unselected. When MORE COLORS is clicked, it does not show color of ColorPicker, instead it selects black color each time.

    I think this control will be more desirable when it correctly identifies the color of ColorPicker.

    Reply
  • Bug in DDX_ColourPicker?

    Posted by Legacy on 02/01/2001 12:00am

    Originally posted by: Dave Steckler

    I'm not an expert on the whole world of DDX and such...but I think there's a major bug in the DDX_ColourPicker function. In particular, you can't do something like:
    
    

    CColourPicker* p = (CColourPicker*)CWnd::FromHandle(hwnd);

    and then do something which actually mucks with a data member of this object (mainly because CWnd::FromHandle just generates a temporary CWnd object, not a CColourPicker object).

    Er....right? (as I said, I'm not an expert in this stuff...)

    So I changed DDX_ColorPicker as follows (basically copied code out of DDX_Control, and then set/get the appropriate value.

    Again, sorry if I'm way off base here. Please let me know if there's a better way to do this.

    ...Dave

    =================================

    void AFXAPI DDX_ColourPicker(CDataExchange *pDX, int nIDC, CColourPicker& Picker, COLORREF& crColour)
    {
    if (Picker.m_hWnd == NULL) // not subclassed yet
    {
    ASSERT(!pDX->m_bSaveAndValidate);

    HWND hWndCtrl = pDX->PrepareCtrl(nIDC);

    if (!Picker.SubclassWindow(hWndCtrl))
    {
    ASSERT(FALSE); // possibly trying to subclass twice?
    AfxThrowNotSupportedException();
    }
    #ifndef _AFX_NO_OCC_SUPPORT
    else
    {
    // If the control has reparented itself (e.g., invisible control),
    // make sure that the CWnd gets properly wired to its control site.
    if (pDX->m_pDlgWnd->m_hWnd != ::GetParent(Picker.m_hWnd))
    Picker.AttachControlSite(pDX->m_pDlgWnd);
    }
    #endif //!_AFX_NO_OCC_SUPPORT

    }

    if (pDX->m_bSaveAndValidate)
    {
    crColour = Picker.GetColour();
    }
    else // initializing
    {
    Picker.SetColour(crColour);
    }
    }

    Reply
  • Possible "Default Color" bug?

    Posted by Legacy on 05/02/2000 12:00am

    Originally posted by: James Southard Jr

    In CColourPicker::DrawItem()
    
    

    CBrush brush( ((state & ODS_DISABLED) || m_crColourBk == CLR_DEFAULT)?
    ::GetSysColor(COLOR_3DFACE) : m_crColourBk);

    Sets the background of the control to either the button
    face default or the selected background color, correct?

    If so, when I select the "Default color" the background of
    the control is set to the default, while the color stored
    in m_crColourBk is changed to black. Is this supposed to be
    the way it behaves, or should the background of the control
    always reflect the current background color?

    One remedy to this would be:

    CBrush brush( m_crColourBk = ((state & ODS_DISABLED) || m_crColourBk == CLR_DEFAULT)?
    ::GetSysColor(COLOR_3DFACE) : m_crColourBk);

    This ensures that the background color is reflected in the
    control's background color.

    Please correct me if I'm wrong.

    Thanks.


    Reply
  • Bug in CColourPicker::OnSelEndOK()

    Posted by Legacy on 04/28/2000 12:00am

    Originally posted by: Xuelong Zhou

    Very nice. Thanks. 
    
    A minor bug in OnSetEndOK() when notify parent window for CPN_SELCHANGE, SetColour() is called too soon.

    LONG CColourPicker::OnSelEndOK(UINT lParam, LONG /*wParam*/)
    {
    COLORREF crNewColour = (COLORREF) lParam;
    // save the flag first ifthe colour is different
    // use it when SendMessage(CPN_SELCHANGE,...)
    BOOL bIsColourDiff=(crNewColour != GetColour());
    m_bActive = FALSE;
    SetColour(crNewColour);

    CWnd *pParent = GetParent();
    if (pParent) {
    pParent->SendMessage(CPN_CLOSEUP, lParam, (WPARAM) GetDlgCtrlID());
    pParent->SendMessage(CPN_SELENDOK, lParam, (WPARAM) GetDlgCtrlID());
    }

    if (bIsColourDiff)
    if (pParent) pParent->SendMessage(CPN_SELCHANGE, lParam, (WPARAM) GetDlgCtrlID());

    return TRUE;
    }

    Reply
  • fix for "more colours" lost focus crash

    Posted by Legacy on 09/22/1999 12:00am

    Originally posted by: rick shide

    try this:
    
    

    void CColourPopup::EndSelection(int nMessage)
    {
    if (!GetSafeHwnd())
    return;
    ...

    This popup is getting destroyed when loosing focus, but is
    still getting and responding to mouse button messages, in
    particular WM_LBUTTONUP that's generated when releasing the
    mouse after picking another application.

    Reply
  • Crash with "more colors"

    Posted by Legacy on 08/19/1999 12:00am

    Originally posted by: Niki Estner

    The control is neat, but it always crashed on my machine (NT4, SP4, IE5, VC6) when I chose the "more colors" item.
    I killed the "DestroyWindow" in OnKillFocus, and it ran fine, yet I guess it must have had some sense...
    (The popup will stay open as long as the ColorDialog is open, but it will close immediately after the ColorDialog is closed.)

    void CColourPopup::OnKillFocus(CWnd* pNewWnd)
    {
    CWnd::OnKillFocus(pNewWnd);

    ReleaseCapture();
    //DestroyWindow();
    }

    Reply
  • Bug in Version 1.3 when losing focus to another application

    Posted by Legacy on 07/18/1999 12:00am

    Originally posted by: Johnny

    void CColourPopup::OnNcDestroy()
    {
    CWnd::OnNcDestroy();
    delete this; // causes crash when Custom colour dialog appears.
    }

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date