Introduction
After creating the CAppBar class, I was hoping to add a button on the caption bar, right next to the Close button to control the autohide
attribute of the AppBar window. To add a button on the caption bar is not as easy as adding normal buttons on the client area. There are some existing applications with a custom button on the caption bar. But we can hardly find the code to implement that (not to say reusable code). So, I decided to create one. That�s CCaptionButton
.
To add a normal window-based button on the caption bar is simply impossible. Those that appear as caption buttons are drawn on the caption bar with a look and feel of the normal buttons. Handling of WM_NCPAINT
message is the main method to achieve that. Of course, other messages like mouse movement should also be handled to achieve real button look and feel.
Prepare images
Since we need to draw the button on the caption, we need to prepare some images to simulate the button. The CCaptionButton
class requires an image list for each button containing the following images:
- Normal status
- Pushed status
- Hover status
- Checked status (optional)
- Disabled status (optional)
The above list is enough for understanding what is what. Here is a sample image to create an image list for our push pin caption button:
Add caption buttons
We have to support multiple caption buttons for one window. Each button is stored internally with the following data structure:
struct _button
{
UINT uID;
int cx;
int cy;
HIMAGELIST himl;
UINT uStatus;
char szHint[80];
};
A vector is used to hold the buttons internally. To add a button, simply call:
int AddButton(UINT uID, int cx, int cy,
HIMAGELIST himl, LPCTSTR lpszHint=NULL);
where
uID
is the command ID of the button. When the button is clicked, a WM_COMMAND
message with a uID
parameter is sent to the window. So, handling a caption button clicking is just the same as handling a normal button clicking.
cx
and cy
specify the size of the button. This size must match the size of the images in the corresponding image list.
himl
holds all the images required to draw the button. It must contain at least three images with the correct order as described previously or up to five images if checked and disabled status is required.
lpszHint
is the tooltip text for the button.
Positioning
Where do we draw these buttons? Auto positioning sounds like a must for a reusable class. However, I found it impossible to put the button at the right place in all window styles.
- Is the window a tool window, which has a relatively thin caption bar?
- Dose the window contain a minimize button?
- Dose the window contain a maximize button?
- Dose the window contain a help button?
- �
All these will make auto positioning a mess. Finally, I decided to let the derived class position the buttons. The function GetButtonPos
is designed to be overridden to provide positions for each button.
POINT GetButtonPos(int index);
The CCaptionButton
class provides a default implementation of GetButtonPos
. But it assumes that the target window is a tool window, and that there are no existing system buttons. For any other style, you have to implement your own GetButtonPos
to position the buttons correctly. By providing a customized GetButtonPos
function, the button positioning becomes more powerful and flexible than auto positioning. You can even stack two buttons vertically, as in the demo application.
Usage
CCaptionButton
class can be easily added to any ATL/WTL window class that is derived from CWindowImpl
directly or indirectly. To conclude the usage:
- Use
CCaptionButton
class as the base class.
- Use
CHAIN_MSG_MAP
to chain messages to CCaptionButton
class.
- Call
AddButton
to add one or more buttons to the caption bar.
- (Important) Override the
GetButtonPos
function to provide positions for each button added.
- Handle the
WM_COMMAND
notification sent by the caption button in the same way as handling a normal button click.
- (Optional) Call
CheckButton
to change the checked status of the caption button.
- (Optional) Call
EnableButton
to change the enable status of the caption button.
Features
- Add one or more buttons to the caption bar.
- Flexible positioning.
WM_COMMAND
support for button clicking.
- Tooltip support.
Sample application
The attached sample application demonstrates the usage of CCaptionButton
. The CAppBar
class is also used for AppBar functionality. To get more details on CAppBar
, check here. Five caption buttons are used in the sample. The pushpin button controls the auto hide attribute of the AppBar window; four other buttons dock the window to the four edges of the screen; and the "Dock bottom" button is disabled, so that you can see how a disabled button would look like.
Enjoy
Well, the code and the sample project are attached. I hope it would be easy to use and simple to read. I also hope some day it would be part of WTL. I was using Visual Studio 2003 and WTL7.5 while writing this code. I did not test it in any other platform. I hope it works well. If it doesn't, send me a message. I'll try to make it better.
Chinese readers, you can check my blog in Chinese. The Chinese version of this article is available here.
Revision
- September 21st, 2005 - Fixed the repaint issue for classic window themes.