Dynamically Switchable Control Type

.


Environment: VC6

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 (eg disable) pairs of
labels and edit controls for instance.

The features are summarised 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 type MCT_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 SetType(MULTICTRLTYPE mct, DWORD dwStyleAdd
= 0, DWORD dwStyleRemove = 0);
sets the control’s current type. The value can be one of the following types:
Type Description
MCT_NONE empty invisible control
MCT_STATIC static control
MCT_STATICBTN static control, with label as button
MCT_EDIT single edit control
MCT_UPDOWNEDIT edit with nested up/down control
MCT_DROPLIST drop-down list
MCT_COMBO combo box
MCT_CHECKBOX check box control
MCT_DATETIME date/time picker
MCT_RICHEDIT rich-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:
Attribute Description
MCA_NORMAL normal – label visible, control visible and enabled
MCA_READONLY label visible and enabled, control visible but disabled
MCA_DISABLED everything visible but disabled
MCA_HIDDEN everything hidden
MCA_NOLABEL label hidden. If type is MCT_STATICBTN, this attribute
causes the label (the button) to be shown, and the static control to
be hidden
MCA_BROWSEBTN include ‘…’ button on the right of the control – currently
only available for MCT_EDIT type controls
MCA_HISTORY combo 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 if 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();
returnsa pointer to the static control, or NULL if the type does not use
a static control
CEdit* 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;
retreives 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

Downloads

Download source – 17.0 Kb

Download demo – 120 Kb

– Version 2.1: Mar 06, 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: Mar 05, 2002

  • added Rich Edit control to available control types
  • added support for ALT+ 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);


More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read