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.
Ravi Bhavnani is an ardent fan of Microsoft technologies who loves building Windows apps, especially PIMs, system utilities, and things that go bump on the Internet. During his career, Ravi has developed expert systems, desktop imaging apps, marketing automation software, EDA tools, a platform to help people find, analyze and understand information, trading software for institutional investors and advanced data visualization solutions. He currently works for a company that provides enterprise workforce management solutions to large clients.
His interests include the .NET framework, reasoning systems, financial analysis and algorithmic trading, NLP, HCI and UI design. Ravi holds a BS in Physics and Math and an MS in Computer Science and was a Microsoft MVP (C++ and C# in 2006 and 2007). He is also the co-inventor of 3 patents on software security and generating data visualization dashboards. His claim to fame is that he crafted CodeProject's "joke" forum post icon.
Ravi's biggest fear is that one day he might actually get a life, although the chances of that happening seem extremely remote.