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
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.
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:
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);
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.
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.
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);
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.
CCaptionButton class can be easily added to any ATL/WTL window class that is derived from
CWindowImpl directly or indirectly. To conclude the usage:
CCaptionButton class as the base class.
CHAIN_MSG_MAP to chain messages to
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.
- Add one or more buttons to the caption bar.
- Flexible positioning.
WM_COMMAND support for button clicking.
- Tooltip support.
The attached sample application demonstrates the usage of
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.
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.
- September 21st, 2005 - Fixed the repaint issue for classic window themes.