Click here to Skip to main content
15,868,236 members
Articles / Desktop Programming / MFC
Article

CCaptionButton (buttons for the titlebar)

Rate me:
Please Sign up or sign in to vote.
4.56/5 (44 votes)
13 Jun 20044 min read 242.8K   10.6K   128   32
Bitmap - buttons for the Titlebar

Sample Image - CCaptionButton.gif

Here are some more images with different button states:

DeActive Image - DeActive.gif

Mouse hover state:

Highlight Image - Highlight.gif

Introduction

This class inserts a variable number of bitmaps to the caption of your dialog and handles them like buttons (next to the close, maximize or minimize button). This means the size and the position will be calculated no matter if there is only 1 button (to close the Dialog) or 3 buttons (to close/maximize/minimize). It is also possible to draw the button to a dialog that has the toolwindow flag or the resizable flag set. The button shows a highlighted state if the mouse hovers above it and gets disabled if the window is deactivated. The reason for me to build this class was to bring a button to the caption of a dialog without using DrawFrameControl, just to get some experience with Bitmaps and the NonClient area.

BTW: Constructive criticism is always welcome! :-)

Using the code:

The code in the demo project is well documented (at least in my view of things ;-)). Take a look!

  1. Add the files CaptionButton.h and CaptionButton.cpp to your project and include the header.
    #include "CaptionButton.h"
  2. Create a member variable of class CCaptionButton.
    i.e.   CCaptionButton *m_pCapBtn // a pointer to CCaptionButton
  3. Call the static function CCaptionButton::InitCapBtn in your dialog's OnInitDialog() handler.
    CCaptionButton::InitCapBtn(m_hWnd);
    • HWND m_hWnd is the handle of the window where the button should be placed.
  4. While we are in the OnInitDialog() part of your dialog's source file, we tell the class some details.

    Therefore we use the member function SetBmpID:

    m_pCapBtn->SetBmpID(1, IDB_LAMPOFF, IDB_LAMPON, FALSE);
    • UINT n (in this case 1) is the number of the button (e.g.: 1 is the rightmost button, then comes button number 2 on the left side of button number 1...)
    • UINT IDB_LAMPOFF is the bitmap for the unpressed button
    • UINT IDB_LAMPON is the bitmap for the button in the pressed state of the button. This can be left clear in case you prefer to use the same bitmap for both button states (pressed/unpressed)
    • BOOL FALSE presents the kind of the button (checkbutton or not). Important only for the hover-drawing.

    You are able to use this function to change the bitmaps somewhere in the code as long as the first argument remains the same.

  5. Now, we have to react on the message WMU_HITCAPBUTTON:

    We want to take some action when the button in the caption is clicked. Every time our button is clicked, a message is sent to our window. That's why we have to add a handler for the registered-message WMU_HITCAPBUTTON. Follow these simple steps to accomplish the task:

    • You define the handler OnWMU_Hitcapbutton in the message handler part of your dialog class' header file. Add the declaration:
      • afx_msg LRESULT OnWMU_Hitcapbutton(WPARAM wParam, LPARAM lParam);
    BEGIN_MESSAGE_MAP(CTitleBarButtonDlg, CDialog)
            //{{AFX_MSG(CTitleBarButtonDlg)
            virtual BOOL OnInitDialog();
            afx_msg void OnPaint();
            afx_msg HCURSOR OnQueryDragIcon();
            afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point);
            afx_msg void OnNcPaint();
            afx_msg void OnDestroy();
            afx_msg BOOL OnNcActivate(BOOL bActive);
            afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
            //}}AFX_MSG
            afx_msg LRESULT OnWMU_Hitcapbutton(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
    • Create an entry in the table to dispatch on these messages, therefore you declare the registered message and add an entry in the message map of your dialog class' source file:
      • For the Registered Message: DECLARE_USER_MESSAGE(WMU_HITCAPBUTTON)
      • The message map entry: ON_REGISTERED_MESSAGE(WMU_HITCAPBUTTON, OnWMU_Hitcapbutton)
    // announce the registered message:
    
    DECLARE_USER_MESSAGE(WMU_HITCAPBUTTON)
    
    BEGIN_MESSAGE_MAP(CTitleBarButtonDlg, CDialog)
            //{{AFX_MSG_MAP(CTitleBarButtonDlg)
            ON_WM_PAINT()
            ON_WM_QUERYDRAGICON()
            ON_WM_NCLBUTTONDOWN()
            ON_WM_NCPAINT()
            ON_WM_DESTROY()
            ON_WM_NCACTIVATE()
            ON_WM_NCMOUSEMOVE()
            //}}AFX_MSG_MAP
            ON_REGISTERED_MESSAGE(WMU_HITCAPBUTTON, OnWMU_Hitcapbutton)
    END_MESSAGE_MAP()

    Please notice that the entries in the message map are written outside the //}}AFX_MSG - MFC-Tags!

    • Now, when your class receives the WMU_HITCAPBUTTON message, it will call the handler for this message which should look like this:
    /***********************************************************************
    *   Message Name:            WMU_HITCAPBUTTON
    *   Inputs:
    *     WPARAM: (UINT)wParam = Nomba of Button
    *     LPARAM: (BOOL)lParam = Button state (Pressed=TRUE/Released=FALSE)
    *
    *   Result: LRESULT
    *                       Logically void, 0, always
    *
    *   Effect: represents the # of the Button (if there is more than one)
    *               and the button state (pressed/released)
    ***********************************************************************/
    LRESULT CTitleBarButtonDlg::OnWMU_Hitcapbutton(WPARAM wParam,
                                                      LPARAM lParam)
    {
            // Button #1 has been hit:
            if((UINT)wParam == 1)
            {
                // button No.1 has been clicked, now do something
    
            }
    
    return 0; // Allways return 0(LRESULT->void)
    }

That's it! Now your button should work.


Additional member functions:

  • A function to enable/disable a button (this routine is implemented but not working on my NT4 even though it works on my XP-Home):
    BOOL CCaptionButton::EnableButton(BOOL bEnable)

Planned but not yet implemented:

  • A function to show/hide a button
  • A function to get/set the state of a button
  • ..... ..... ..... .....
  • Suggestions for more are welcome!

    These are the messages that are handled in class CCaptionButton:

    • WM_NCPAINT: This is where the button will be drawn to the caption.
    • WM_NCACTIVATE: The active/inactive state of the dialog will be "changed" here.
    • WM_NCLBUTTONDOWN: The mouse-clicks will be handled here.
    • WM_NCMOUSEMOVE: Here the button will be told when the mouse hovers over it.
    • WM_SETTEXT: This message must be handled, otherwise the caption will change in a way I don't like ;-)

    Credits

    • If you want to know more about messaging, you should read the excellent essay from Joseph M. Newcomer
    • Paul Di Lascia. I reused his code in isWindowActive(...).
    • For a Win32 implementation, look here.

    UPDATES:

    • 04.06.2004
      • TRACKMOUSEEVENT structure added
      • TrackMouseEvent(TRACKMOUSEEVENT lpEventTrack) - function added
      • Message-handling for WM_NCMOUSELEAVE added
      • changed some values in COLORADJUSTMENT structure
    • 11.06.2004
      • solved Problem for disappearing buttons on right-mouseclick in NC-area
      • solved problem for delay of drawing the buttons when dialog is re-activated by a left-mouseclick in the NC-area

    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


    Written By
    Web Developer
    Germany Germany
    My name is Thomas, I'm born on January the 11th in
    1970, right now I'm working in the Quality department
    of a big Pipe mill as a Technician.
    My hobbies are my girl friend, my car, RC-Planes and
    Computers. I begun with VC++ some time ago and now
    Programming is like a drug to me (I'm still a
    beginner). I want to learn it all in a blink of an
    eye Wink | ;-) but i know that this is not possible. It's
    real fun for me and I do small Programms for my own
    use.
    O.K. enough written..... I need my Time to debug
    everything that crosses my way! Wink | ;-)

    Comments and Discussions

     
    QuestionFor Win32 link is dead =( Pin
    Avtem6-Jan-21 20:56
    Avtem6-Jan-21 20:56 
    GeneralCaption buttons do not appear in Windows 7 Pin
    masteryoda215-Sep-10 20:11
    masteryoda215-Sep-10 20:11 
    GeneralRe: Caption buttons do not appear in Windows 7 Pin
    minregol10-Feb-11 3:07
    minregol10-Feb-11 3:07 
    GeneralRe: Caption buttons do not appear in Windows 7 Pin
    Lomeo16-Sep-11 4:54
    Lomeo16-Sep-11 4:54 
    GeneralRe: Caption buttons do not appear in Windows 7 Pin
    YuGuoLong23-Feb-12 4:18
    YuGuoLong23-Feb-12 4:18 
    GeneralRe: Caption buttons do not appear in Windows 7 Pin
    kissLife28-Oct-13 16:29
    kissLife28-Oct-13 16:29 
    GeneralRe: Caption buttons do not appear in Windows 7 Pin
    wild farmer24-Mar-16 23:42
    wild farmer24-Mar-16 23:42 
    GeneralWarning this class does not work with Windows Home Server (or Windows 2003) Pin
    Lars [Large] Werner23-Jan-09 12:09
    professionalLars [Large] Werner23-Jan-09 12:09 
    GeneralRe: Warning this class does not work with Windows Home Server (or Windows 2003) Pin
    binyo6629-Jun-09 4:28
    binyo6629-Jun-09 4:28 
    QuestionUse in another applications Pin
    vic_mrh5-Aug-08 1:19
    vic_mrh5-Aug-08 1:19 
    Hello,

    I want to know if it is possible to use this in order to put the button in all active applications.
    I would be so grateful if you could send me some information about how I can do this...

    Thanks in advance...
    QuestionTooltips? Pin
    matt20001-Sep-06 5:37
    matt20001-Sep-06 5:37 
    GeneralButton does not work after openfile dialog Pin
    cnstim14-Feb-06 13:31
    cnstim14-Feb-06 13:31 
    GeneralRe: Button does not work after openfile dialog Pin
    cnstim14-Feb-06 14:03
    cnstim14-Feb-06 14:03 
    GeneralWM_NCMOUSEMOVE don't work Pin
    Svetoslav Chekanov10-Aug-05 23:37
    Svetoslav Chekanov10-Aug-05 23:37 
    GeneralRe: WM_NCMOUSEMOVE don't work Pin
    jtwang6-Jul-06 10:05
    jtwang6-Jul-06 10:05 
    GeneralRemoveProp() Pin
    x-bay8-Feb-05 4:30
    x-bay8-Feb-05 4:30 
    GeneralRe: RemoveProp() Pin
    Thomas Latuske9-Feb-05 6:20
    Thomas Latuske9-Feb-05 6:20 
    GeneralRe: RemoveProp() Pin
    Thomas Latuske9-Feb-05 6:30
    Thomas Latuske9-Feb-05 6:30 
    GeneralRe: RemoveProp() Pin
    x-bay9-Feb-05 11:50
    x-bay9-Feb-05 11:50 
    GeneralA problem Pin
    Piccinano14-Nov-04 0:49
    Piccinano14-Nov-04 0:49 
    Generalusing menu Pin
    slubka9-Sep-04 3:00
    slubka9-Sep-04 3:00 
    GeneralRe: using menu Pin
    Thomas Latuske9-Sep-04 6:24
    Thomas Latuske9-Sep-04 6:24 
    GeneralRe: using menu Pin
    slubka13-Sep-04 20:43
    slubka13-Sep-04 20:43 
    GeneralRe: using menu Pin
    brushington22-Aug-07 10:40
    brushington22-Aug-07 10:40 
    GeneralRe: using menu Pin
    brushington22-Aug-07 21:04
    brushington22-Aug-07 21:04 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.