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.
- 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.
- 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
.
- 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).
- Set the text for the control to the initial label text you wish to use.
- 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
.
- 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);
m_ctrl.SetValueText("Hello");
m_ctrl.SetHelpString("This is my control");
(see the documentation for SetType() for other control types)
- 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:
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 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