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
|
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); | |