Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CCaptionButton - Add Buttons on the Caption Bar

0.00/5 (No votes)
19 Sep 2005 1  
A reusable WTL base class to add buttons on the caption bar.

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;        //command ID

        int        cx;          //width

        int        cy;          //height

        HIMAGELIST    himl;     //image list

        UINT        uStatus;    //status (image index)

        char        szHint[80]; //tooltip text

    };

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:

  1. Use CCaptionButton class as the base class.
  2. Use CHAIN_MSG_MAP to chain messages to CCaptionButton class.
  3. Call AddButton to add one or more buttons to the caption bar.
  4. (Important) Override the GetButtonPos function to provide positions for each button added.
  5. Handle the WM_COMMAND notification sent by the caption button in the same way as handling a normal button click.
  6. (Optional) Call CheckButton to change the checked status of the caption button.
  7. (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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here