FooButton






4.85/5 (115 votes)
A lightweight general-purpose owner drawn bitmap button.
Introduction
This article describesFooButton
, 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
- 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.///////////// // MyDialog.h #include "FooButton.h" ... FooButton m_fooButton;
/////////////// // MyDialog.cpp void CMyDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMyDialog) DDX_Control(pDX, IDC_FOO_BUTTON, m_fooButton); //}}AFX_DATA_MAP }
- 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.
// Initialize FooButton m_fooButton.setBitmapId (IDB_FOO_BUTTON); m_fooButton.setType (FooButton::Type::pushButtonDropDown);
API
|
|
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. Usecheck()
and
isChecked()
to set and retrieve the button's checked state.
// Make it a checkbutton and check it m_fooButton.setType (FooButton::Type::checkButton); m_fooButton.check (true); ASSERT (m_fooButton.isChecked()); // testing |
![]() ![]() |
Gradient shading
Pushbuttons and checkbuttons can be set to display a gradient shaded background by callingsetGradient()
. This
method has no effect if the button isn't a pushbutton or checkbutton.
// Use a gradient shaded background m_fooButton.setGradient (true); |
![]() |
Button groups
You can make a bunch ofcheckButton
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.
// Make "size" checkbuttons mutually exclusive 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, calldisplayPopupMenu()
. 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()) { // Display menu if drop-down region was clicked 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); // Remember to clear the button's multi-click property! m_fooButton.clearMultiClick(); } else { // Otherwise do default action PostMessage (WM_COMMAND, IDC_DEFAULT_ACTION); } } |
![]() ![]() |
Check boxes and radio buttons
You can make aFooButton
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.
// Appear as check box and radio 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.
// Appear as hyperlink
m_fooButton.setType (FooButton::Type::hyperink);
|
![]() |
Text color
You can change the color of the button's text at any time by callingsetTextColor()
. The text of hyperlink buttons is
always rendered in C_HyperlinkColor
and that of disabled buttons is
always rendered in the standard etched format.
// Draw caption in red m_fooButton.setTextColor (RGB (192, 0, 0)); |
![]() |
Focus rectangle
By default, aFooButton
doesn't display a
focus rectangle. Call setFocusStyle()
with
FooButton::Focus::normalFocus
to enable the button to display a
focus rectangle.
// Allow focus rectangle to be displayed
m_fooButton.setFocusStyle (FooButton::Focus::normalFocus); |
![]() ![]() |
Default button indicator
To enable a defaultFooButton
to
display its standard dark border, call setFocusStyle()
with
FooButton::Focus::defaultFocus
.
// Allow focus rectangle and default indicator to be displayed
m_fooButton.setFocusStyle (FooButton::Focus::defaultFocus); |
![]() ![]() |
Rendering disabled bitmaps
Use the standard MFCEnableWindow()
API to enable and disable the button.
FooButton
uses its original bitmap to render a disabled version.
m_fooButton.EnableWindow (TRUE); // enable button m_fooButton.EnableWindow (FALSE); // disable button |
![]() ![]() |
Acknowledgement
- Drawing a bitmap transparently by Zafir Anjum
- Draw bitmap with grayed 3D effect by Jean-Edouard Lachand-Robert
- Hyperlink control by Chris Maunder
- A Gradient Static Control by Irek Zielinski
- Thanks to those who've reported bugs, identified solutions and suggested features!
Revision history
- Bug Fix:
m_hMsimg32
should be set toNULL
in destructor. (Thanks, C. Young!) - Bug Fix: Memory leak in
DisabledBlt()
. (Thanks, Corrado Valli!)
- Bug Fix: Added definition of
COLOR_HOTLIGHT
to enable compilation on older systems.
- Enhancement: Added support for gradient shaded buttons.
- Bug Fix: Reusing a group name across dialog invocations would
cause a crash in
FooButton::removeFromGroup()
.
- 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 aFooButton
to be safely destroyed when clicked.
- Added support for check boxes and radio buttons
- Fixed typo in default state rendering logic
- Optimized fix for "unreferenced identifier" compiler warning
- Exposed focus rectangle and default state modes
- Added support for button groups
Added multi-pushbutton and hyperlink styles.
Submitted to CodeProject.
Initial version.