Introduction
This article describes
FooButton
, a
lightweight owner-drawn button class that's served me well for several
years. Although there are plenty of other
excellent button classes at
CodeProject, I thought I'd add this trusty friend to the pile in the hope that
someone may find it equally useful.
Features
FooButton
lets you use a vanilla
CButton
as a:
- standard pushbutton
- pushbutton button with a drop-down indicator
- multi pushbutton (like IE's "Back" and "Next" buttons)
- checkbutton
- hyperlink
- static text control that's responsive to mouse clicks
- check box
- radio button
Support is also provided for:
- bitmaps (currently only 16-color)
- left-justified, centered and multi-line captions
- colored captions
- gradient shaded button backgrounds
- popup menus
- hot tracking
- optional focus rectangle and "default button" indicator
- grouped checkbuttons
How to use FooButton
- First, associate a standard button control (eg:
IDC_FOO_BUTTON
)
in your dialog with an instance of the object.
#include "FooButton.h"
...
FooButton m_fooButton;
void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_FOO_BUTTON, m_fooButton);
}
|
- Then, initialize the instance in your dialog's OnInitDialog() method to suit
your needs. In this example, the button is set to display a bitmap and a
drop-down indicator.
m_fooButton.setBitmapId (IDB_FOO_BUTTON);
m_fooButton.setType (FooButton::Type::pushButtonDropDown);
|
|
API
Method | Purpose | getType(), setType() | Gets and sets the button's type | getTextStyle(), setTextStyle() | Gets and sets the button's text style | getTextColor(), setTextColor() | Gets and sets the button's text color | getFocusStyle(), setFocusStyle() | Gets and sets the button's focus style | |
getGradient(), setGradient() | Gets and sets the button's gradient property | getBitmapId(), setBitmapId() | Gets and sets the button's (optional) bitmap
id |
|
displayPopupMenu() | Displays a popup menu below the button | isChecked(), check() | Gets and sets a checkButton 's checked state | isMultiClicked(), clearMultiClick() | Gets and resets a multiPushButton 's multi-clicked
state | addToGroup(), removeFromGroup() | Adds/removes a checkButton to/from a button
group | reset() | Frees storage used by all button
groups |
|
Using FooButton as a check button
You can freely change any property of
the button at run time. This code snippet turns the button into a
checkbutton and checks it. Use
check()
and
isChecked()
to set and retrieve the button's checked state.
m_fooButton.setType (FooButton::Type::checkButton);
m_fooButton.check (true);
ASSERT (m_fooButton.isChecked());
| |
Gradient shading
Pushbuttons and checkbuttons can be set to display a
gradient shaded background by calling
setGradient()
. This
method has no effect if the button isn't a pushbutton or checkbutton.
m_fooButton.setGradient (true);
| |
Button groups
You can make a bunch of
checkButton
s behave
as mutually exclusive radio buttons by adding them to a button group. A
button group is just a named collection of buttons.
FooButton
automatically handles group creation, membership and cleanup.
m_btnSmall.addToGroup (_T("foo"));
m_btnMedium.addToGroup (_T("foo"));
m_btnLarge.addToGroup (_T("foo"));
m_btnXLarge.addToGroup (_T("foo"));
| |
Displaying a popup menu
To display a popup menu in response to a button
click, call
displayPopupMenu()
. You can call this method for
any type of
FooButton
.
void CMyDialog::OnFooButton()
{
CMenu menu;
menu.LoadMenu (IDR_POPUP_MENU);
CMenu* pPopupMenu = menu.GetSubMenu (0);
int nResult = m_fooButton.displayPopupMenu (pPopupMenu);
if (0 != nResult)
PostMessage (WM_COMMAND, nResult);
}
|
|
Multi-pushbuttons
A multi-pushbutton behaves as two buttons in one,
similar to IE's "Back" and "Next" buttons. When the user clicks the
button's drop-down region,
FooButton
sets its "multi-clicked"
property to
true
. You can query this property by calling
isMultiClicked()
. Regardless of whether the user clicked in
the button's main or drop-down region, a standard notification is sent to the
parent. To clear the button's multi-click property, call
clearMultiClick()
.
void CMyDialog::OnFooButton()
{
if (m_fooButton.isMultiClicked()) {
CMenu menu;
menu.LoadMenu (IDR_POPUP_MENU);
CMenu* pPopupMenu = menu.GetSubMenu (0);
int nResult = m_fooButton.displayPopupMenu (pPopupMenu);
if (0 != nResult)
PostMessage (WM_COMMAND, nResult);
m_fooButton.clearMultiClick();
} else {
PostMessage (WM_COMMAND, IDC_DEFAULT_ACTION);
}
}
| |
Check boxes and radio buttons
You can make a
FooButton
appear as a standard check box or radio button by using the
FooButton:Type::checkBox
and
FooButton:Type::radio
types. Of course, this is really only useful when you want to also display
a bitmap or add menu support to the button.
m_fooButton1.setType (FooButton::Type::checkBox);
m_fooButton2.setType (FooButton::Type::radio);
| |
Hyperlink button
A hyperlink button is just a regular button that
renders itself as a hyperlink. You can navigate to a URL or perform any
other action in the button's handler.
m_fooButton.setType (FooButton::Type::hyperink);
| |
Text color
You can change the color of the button's text at any time by
calling
setTextColor()
. The text of hyperlink buttons is
always rendered in
C_HyperlinkColor
and that of disabled buttons is
always rendered in the standard etched format.
m_fooButton.setTextColor (RGB (192, 0, 0));
| |
Focus rectangle
By default, a
FooButton
doesn't display a
focus rectangle. Call
setFocusStyle()
with
FooButton::Focus::normalFocus
to enable the button to display a
focus rectangle.
m_fooButton.setFocusStyle (FooButton::Focus::normalFocus);
|
|
Default button indicator
To enable a default
FooButton
to
display its standard dark border, call
setFocusStyle()
with
FooButton::Focus::defaultFocus
.
m_fooButton.setFocusStyle (FooButton::Focus::defaultFocus);
| |
Rendering disabled bitmaps
Use the standard MFC
EnableWindow()
API to enable and disable the button.
FooButton
uses its original bitmap to render a disabled version.
m_fooButton.EnableWindow (TRUE);
m_fooButton.EnableWindow (FALSE);
|
|
Acknowledgement
Revision history
7 Oct 2006
- Bug Fix:
m_hMsimg32
should be set to NULL
in destructor.
(Thanks, C. Young!)
- Bug Fix: Memory leak in
DisabledBlt()
.
(Thanks, Corrado Valli!)
6 Mar 2005
- Bug Fix: Added definition of
COLOR_HOTLIGHT
to
enable compilation on older systems.
5 Mar 2005
- Enhancement: Added support for gradient shaded buttons.
- Bug Fix: Reusing a group name across dialog invocations would
cause a crash in
FooButton::removeFromGroup()
.
19 Feb 2005
- Enhancement: Added support for colored captions.
- Enhancement: Removed requirement to call
FooButton::reset()
when your app terminates.
- Enhancement: Now uses standard Win2000/XP hyperlink cursor.
- Enhancement: Code now
ASSERT
s if you're not
subclassing from a button control.
- Bug Fix: All calls to
Invalidate()
now validate
window handle, allowing a FooButton
to be safely destroyed when
clicked.
Fixed typo in default state rendering logic
17 Jul 2004
- Added support for check boxes and radio buttons
- Fixed typo in default state rendering logic
11 Jul 2004
- Optimized fix for "unreferenced identifier" compiler warning
- Exposed focus rectangle and default state modes
- Added support for button groups
4 Jul 2004
Added multi-pushbutton and hyperlink styles.
3 Jul 2004
Submitted to CodeProject.
12 Sep 1998
Initial version.