Click here to Skip to main content
15,867,330 members
Articles / Desktop Programming / MFC
Article

Dynamically switchable multi-purpose control

Rate me:
Please Sign up or sign in to vote.
4.43/5 (9 votes)
5 Mar 2002CPOL10 min read 149.1K   2.2K   57   27
Control which allows run-time switching between a number of control types, eg combo, edit etc

Sample Image - MultiCtrl_demo.jpg

Introduction

I frequently find a need to have a control that needs to be represented differently at run-time depending on various circumstances.

The control presented here can be switched at run-time between a number of controls including edit, combobox, static, and checkbox controls. Another advantage is that this control will contain both the label and the 'user' control items (edits/combos/etc), which makes it easier to work with (e.g. disable) pairs of labels and edit controls for instance.

The features are summarized below:

  • Dynamically switchable at run-time to one of a number of controls - Can be made to behave as an edit, combo, static, checkbox, or date/time control simply by setting its type at run-time
  • Eases use of control/label pairings - The control can contain both the label and the user input control, thus making the pair easy to disable, hide, move etc
  • Makes it easy to add tool-tips to controls - The control may have tool-tip text set for it which appears for both the input control and the label. CMultiCtrl manages the enabling and disabling of tool-tips
  • Provides status-bar help text for user while entering data into the control - If tool-tip text has been set for the control, then, when the focus is set to the control the tool-tip text appears in the status bar
  • Still allows working directly with underlying controls - CMultiCtrl has methods which return (a pointer to) the underlying controls, eg GetEditCtrl(), which allows you to easily manipulate the control contents directly

How to use it

Follow the steps below to add a CMultiCtrl to an existing project.

  1. After putting the source files (MultiCtrl.cpp/h and BrowseEdit.cpp/h) into the directory you wish to use them from, add the files to your Visual Studio project. Note also, that MultiCtrl uses my previously published CHistoryCombo, which can be found here, so HistoryCombo.cpp/h need adding to your project.
  2. In the resource editor, add a static (label) control where you wish to have your switchable control. Give it an ID other than the default IDC_STATIC, eg IDC_CTRL_1.
  3. Resize the static control to reflect the size you wish to use for the mutli-ctrl. I find it easier to work with the controls if I set the control to be centred vertically, and to have a client-edge. (Don't give it a border, as this cannot be removed at run-time).
  4. Set the text for the control to the initial label text you wish to use.
  5. Using the Class Wizard, add a member variable for your static control, selecting "Control" from the "Category" list, and selecting "CMultiCtrl" from the "Variable Type" list. (If CMultiCtrl does not appear in the list, you may need to delete your class wizard file (.clw) and regenerate it). I will assume your control variable name is m_ctrl.
  6. Add a handler for WM_INITDIALOG in your dialog class if you don't already have one, and add the following code to it:
    m_ctrl.SetType(MCT_EDIT); // set the control's type
    m_ctrl.SetValueText("Hello"); // set the initial edit control text
    m_ctrl.SetHelpString("This is my control"); 
      // set the tool-tip/status-bar text

    (see the documentation for SetType() for other control types)

  7. In order to set and get the value, or the label, use the following functions:

    To set the value:

    m_ctrl.SetValueText("New control text");

    To get the value:

    CString sText = m_ctrl.GetValueText();

Notes on usage

As the CMultiCtrl type is changed, the underlying controls get destroyed/created as necessary. While the value text, label text, and help-string are preserved, any other state in the controls is not. For instance, if you are using the control with typeMCT_COMBO, and you have added items to the underlying combo's list, then on switching it to another type the list contents will be lost.

In a similar way, changing the styles of a control, using SetType() may cause the control to be destroyed and recreated. This is due to the fact that some control styles can only be set at the time of creation of the control.

Documentation

The list below shows the public functions of the CMultiCtrl class:

void <A name=SetType></A>SetType(MULTICTRLTYPE mct, DWORD dwStyleAdd = 0, DWORD dwStyleRemove = 0);  

Sets the control's current type. The value can be one of the following types:

TypeDescription
MCT_NONEempty invisible control
MCT_STATICstatic control
MCT_STATICBTNstatic control, with label as button
MCT_EDITsingle edit control
MCT_UPDOWNEDITedit with nested up/down control
MCT_DROPLISTdrop-down list
MCT_COMBOcombo box
MCT_CHECKBOXcheck box control
MCT_DATETIMEdate/time picker
MCT_RICHEDITrich-edit control

This function also allows a style to be specified for the underlying control. For example, when using a control as a combo-box, you could ensure that the list is not sorted, and that the edit control auto-scrolls, using the following code:

m_ctrl.SetType(MCT_COMBO, CBS_AUTOHSCROLL, CBS_SORT); 

MULTICTRLTYPE GetType();

Returns the control's current type, as value from the table above

void SetAttributes(int nAttrib);

Sets the attributes of the control. The value can be a combination of the following values:

AttributeDescription
MCA_NORMALnormal - label visible, control visible and enabled
MCA_READONLYlabel visible and enabled, control visible but disabled
MCA_DISABLEDeverything visible but disabled
MCA_HIDDENeverything hidden
MCA_NOLABELlabel hidden. If type is MCT_STATICBTN, this attribute causes the label (the button) to be shown, and the static control to be hidden
MCA_BROWSEBTNinclude '...' button on the right of the control - currently only available for MCT_EDIT type controls
MCA_HISTORYcombo box is a history combo

Note that MCA_NORMAL, MCA_READONLY, MCA_DISABLED, and MCA_HIDDEN should be considered as being mutually exclusive.

int GetAttributes();

Returns the controls currently set attributes, as listed above

void SetHelpString(LPCSTR lpszHelpString);

Sets the tool-tip/status-bar text. If lpszHelpString is NULL or points to an empty string, tool-tips are cleared, and disabled

CString GetHelpString();

Returns the current tool-tip/status-bar text set for the control

void SetLabelWidth(int nWidth = MCSLW_DEFAULT);

Sets the width of the label. If nWidth is MCSLW_DEFAULT it is a pre-defined default width, else nWidth is MCSLW_AUTO

int GetLabelWidth(BOOL bAuto = FALSE);

Returns the width of the label. If bAuto is TRUE, returns the width which would be used if the label was set to auto-size

BOOL IsValueChanged();

Returns whether the user has changed the value text since the last call to SetValueText

void EnableControl(BOOL bEnable = TRUE);

Enables or disables the control

void ResetContent();

Clears the value of the control, and also clears the drop-down list if the control is currently a drop-list or combo

CString GetTypeName();

Returns a string representation of the current control type eg "MCT_EDIT". Can be used for debugging.

CButton* GetButtonCtrl();

Returns a pointer to the button control, or NULL if type does not use a button

CDateTimeCtrl* GetDateTimeCtrl();

Returns a pointer to the date/time control, or NULL if type does not use a date/time control

CHistoryCombo* GetComboCtrl();

Returns a pointer to the combo-box control, or NULL if type doed not use a combo-box

CStatic* GetLabelStaticCtrl();

Returns a pointer to the label static control, or NULL if label is not used, or if it is a button

CStatic* GetStaticCtrl();

Returns a pointer to the static control, or NULL if the type does not use a static control

CEdit* <A name=GetEditCtrl></A>GetEditCtrl();

Returns a pointer to the edit control, or NULL if the type does not use an edit control

CSpinButtonCtrl* GetSpinCtrl();

Returns a pointer to the up/down control, or NULL if type does not use an up/down control

void AddListItems(CStringList& list);

Adds string items to the combo control's list, if the type uses a combo-box.

void AddListItem(LPCTSTR lpszText);

Adds a string item to the combo control's list, if the type uses a combo-box

CString GetValueText() const;

Returns the current value text

void SetValueText(LPCTSTR lpszValue);

Sets the value text to the value pointed to by lpszValue

CString GetLabelText() const;

Returns the current label text

void SetLabelText(LPCTSTR lpszString);

Sets the control's label text

int GetWindowText (LPTSTR lpszBuffer, int nMax) const;

Retrieves the control's value text

void GetWindowText (CString &rText) const;

Retrieves the control's value text

int GetWindowTextLength() const;

Returns the length of the control's current value text

void SetWindowText(LPCTSTR lpszText);

Sets the control's value text

void SetFont(CFont *pFont, BOOL bRedraw = TRUE);

Sets the current font for the control

void SetTextLimit(UINT nMax);

Sets the maximum length of text that be entered in the control when the control includes an edit control, or combo-box

BOOL Create(LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff);

Used for creating the control dynamically

virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);

Used for creating the control dynamically

void CheckBoxUseLabel(BOOL bUseLabel = TRUE);

For a checkbox, uses the label text as the checkbox text, instead of the value text

void OffsetCheckbox(BOOL bOffset = TRUE);

Makes the left edge of the text box line up with the left edge of edit controls etc, ie it moves the checkbox right by the label width

void SetCheckText(LPCSTR lpszChecked, LPCSTR lpszUnchecked, LPCSTR lpszIndeterminate = NULL);

Specifies what text values should represent the checked/unchecked/indeterminate states of the checkbox. When getting getting the value of the checkbox, the string returned will be the string representing the current check-state

void SetCheckText(CStringList& slistChecked, CStringList& slistUnChecked, CStringList& slistIndeterminate);

Specifies lists of possible text values which should represent the checked/unchecked/indeterminate states of the checkbox. When getting getting the value of the checkbox, the string returned will be the first string in the list representing the current check-state

int GetCheckState(LPCSTR lpszValue);

Returns the check-state represented by the value specified. If no strings match then BST_UNCHECKED is returned

int GetEditSettings(int& nStart, int &nEnd);

Retrieves the current selection settings of the edit control, if the control is currently set to be an edit control. The start and end of the current selection are returned in nStart and nEnd respectively. The function returns the first visible line

void SetEditSettings(int nStart, int nEnd, int nFirst);

Sets the edit control's selection to the values specified for the nStart and nEnd, if the control is currently set to be an edit control. The nFirst parameter specifies the first line which should be visible (applies only to multi-line edit controls)

void Initialise();

Sets up the control's font, dialog units, and initial type and attributes. Called from PreSubclassWindow(), and Create()

virtual CWnd* GetMainCtrl();

Returns a CWnd* which points to the current 'main' control. So, for example, if the control is currently set to an edit control, this returns (CWnd*)GetEditControl()

BOOL IsValueChanged(LPCSTR lpszValue);

If lpszValue is NULL, returns TRUE; if the value has been changed by the user since the last call to SetValueText(), else FALSE. If lpszValue is non-NULL, then the function just returns whether the control contains that value.

CRichEditCtrl* GetRichEditCtrl();

Returns a pointer to the rich edit control, or NULL if type does not use a rich edit control

CButton* GetLabelButtonCtrl();

Returns a pointer to the button used for the label control, or NULL if the control type is not MCT_STATICBTN

void ModifyAttributes(int nAdd, int nRemove = 0);

Modifies the control's current attributes

int AddListItems(CStringList& list);

If the control is set to use a combo-box, then this function adds the items specified in list as combo list items, and returns the number of items added. The return value is -1 if the control does not use a combo-box

int AddListItem(LPCTSTR lpszText);

If the control is set to use a combo-box, then this function adds the item specified in lpszText to the combo's list, and returns the list index of the item. The return value is -1 if the control does not use a combo-box, or if lpszText is NULL

History

  • Version 2.1 - 06 Mar 2002

    • Modified CBrowseEdit so that when it is created with ES_READONLY, the button is disabled. (Thanks to Ernest Laurentin for pointing out this omission!)
  • Version 2 - 05 Mar 2002

    • added Rich Edit control to available control types
    • added support for ALT+<key> accelerators
    • improved check-box support - now takes lists of strings to use for each of the check states
    • new public functions:
      • BOOL Create(LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff);
      • virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
      • void CheckBoxUseLabel(BOOL bUseLabel = TRUE);
      • void OffsetCheckbox(BOOL bOffset = TRUE);
      • void SetCheckText(LPCSTR lpszChecked, LPCSTR lpszUnchecked, LPCSTR lpszIndeterminate = NULL);
      • void SetCheckText(CStringList& slistChecked, CStringList& slistUnChecked, CStringList& slistIndeterminate);
      • int GetCheckState(LPCSTR lpszValue);
      • void SetEditSettings(int nStart, int nEnd, int nFirst);
      • int GetEditSettings(int& nStart, int &nEnd);
      • void Initialise();
      • virtual CWnd* GetMainCtrl();
      • BOOL IsValueChanged(LPCSTR lpszValue);
      • CRichEditCtrl* GetRichEditCtrl();
      • CButton* GetLabelButtonCtrl();
      • void ModifyAttributes(int nAdd, int nRemove = 0);
      • int AddListItems(CStringList& list);
      • int AddListItem(LPCTSTR lpszText);
  • Version 1 - 02 Aug 2001

    • First version

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)
United Kingdom United Kingdom
Originally from an electronics background, I moved into software in 1996, partly as a result of being made redundant, and partly because I was very much enjoying the small amount of coding (in-at-the-deep-end-C) that I had been doing!

I swiftly moved from C to C++, and learned MFC, and then went on to real-time C on Unix. After this I moved to the company for which I currently work, which specialises in Configuration Management software, and currently program mainly in C/C++, for Windows. I have been gradually moving their legacy C code over to use C++ (with STL, MFC, ATL, and WTL). I have pulled in other technologies (Java, C#, VB, COM, SOAP) where appropriate, especially when integrating with third-party products.

In addition to that, I have overseen the technical side of the company website (ASP, VBScript, JavaScript, HTML, CSS), and have also worked closely with colleagues working on other products (Web-based, C#, ASP.NET, SQL, etc).

For developing, I mainly use Visual Studio 2010, along with an in-house-designed editor based on Andrei Stcherbatchenko's syntax parsing classes, and various (mostly freeware) tools. For website design, I use Dreaweaver CS3.

When not developing software, I enjoy listening to and playing music, playing electric and acoustic guitars and mandolin.

Comments and Discussions

 
Generalcombo... Pin
2-Aug-01 4:16
suss2-Aug-01 4:16 
GeneralRe: combo... Pin
Paul Vickery2-Aug-01 22:36
professionalPaul Vickery2-Aug-01 22:36 

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

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