Click here to Skip to main content
15,889,462 members
Articles / Programming Languages / C++

Owner Draw Button Helper Class

Rate me:
Please Sign up or sign in to vote.
2.20/5 (14 votes)
5 Nov 2007CPOL3 min read 43.1K   1.2K   26   5
An intermediate class to create owner draw buttons.

Screenshot - Screen1.jpg

Introduction

This is simply a presentation of a class which can be used as an intermediate class for owner draw buttons.

Using the code

When an owner draw button is created, we begin like...

C++
class CMyButton : public CButton
{
    // class content related custom drawing
};

What I did was that I derived a class from CButton named CODBaseBtn, that does nothing related to drawing. Instead, some virtual functions are called. This made it an intermediate class for owner draw buttons.

C++
class CODBaseBtn : public CButton
{
    // Basic handling of events and virtual functions for drawing
}

There are two kinds of virtual functions provided:

  1. Drawing related
  2. Action related

The drawing related virtual functions are as follows...

C++
virtual void OnDrawNormal( CDC& dc, CRect rect ) = 0;
virtual void OnDrawHovered( CDC& dc, CRect rect ) { OnDrawNormal( dc, rect ); }
virtual void OnDrawPressed( CDC& dc, CRect rect ) { OnDrawNormal( dc, rect ); }
virtual void OnDrawDisabled( CDC& dc, CRect rect ) { OnDrawNormal( dc, rect ); }

The first function is pure virtual, which must be implemented by the derived classes. As the names imply, these functions are called on the corresponding conditions. So the derived class can handle them and draw the appropriate button images.

The action related virtual functions are as follows...

C++
virtual void OnBeginHover() { }
virtual void OnEndHover() { }
virtual void OnPressed() { }
virtual void OnReleased() { }

They are called on the actions like mouse hover, mouse leave, press, and release, respectively. They can be used wisely to extend the functionality of a normal button. They are not pure virtual, so they can be avoided if not needed.

Deriving a class from CODBaseBtn is as shown...

C++
class CMyBtn : public CODBaseBtn
{
    // Implementation of custom drawings and actions.
}

Sample application

The sample test application has two derived classes. One is just using the drawing related functions. While the other uses both drawing and action related functions. From that, the possibilities of such a class can be understood.

The drawing done is very simple since the test application is just for illustrating the use of CODBaseBtn.

Inside CODBaseBtn

The main code inside CODBaseBtn is described here:

C++
void CODBaseBtn::PreSubclassWindow()
{
    // Some code...


    // Update the style to owner draw
    ModifyStyle( 0, BS_OWNERDRAW );

    // Some code...
}

The style is set to BS_OWNERDRAW for enabling the button owner draw. This helps to avoid setting this style when the button is created, either in the dialog resource editor or at run time using Create (or CreateWindow).

C++
void CODBaseBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    // The virtual functions are called from here
}

DrawItem is a virtual function of CButton. It is called when the button needs to be drawn. The lpDrawItemStruct will contain the necessary things for drawing, like hDC, client rectangle, state of the button, etc. Using these, the appropriate virtual functions for drawing and action are called.

C++
void CODBaseBtn::OnMouseMove(UINT nFlags, CPoint point)
{
    if( !m_bMouseHover )
    {
        // Set the flag so that next mouse move message will be neglected
        m_bMouseHover = true;

        // Some code to register the mouse leave message
    }
}

This is for mouse hover handling. When the mouse is inside the button, m_bMouseHover will be false (which is initially set as false). And inside the function, it is set as true. So when the mouse moves inside the button the next time, it can be neglected. The first time, the corresponding drawing and action functions are called and the mouse leave message request is registered using _TrackMouseEvent. The following function will be called when the mouse leaves the button (client) area.

C++
LRESULT CODBaseBtn::OnMouseLeave( WPARAM, LPARAM )
{
    // Reset the flag
    m_bMouseHover = false;

    // Some code...

    return 0;
}

Here, m_bMouseHover is reset to false. And the necessary calls to drawing and action functions are called:

C++
void CODBaseBtn::OnLButtonDblClk(UINT nFlags, CPoint point)
{
    // Convert the double click to single click
    const MSG* pstMSG = GetCurrentMessage();
    DefWindowProc( WM_LBUTTONDOWN, pstMSG->wParam, pstMSG->lParam );
}

This is a tricky one. Buttons having the BS_OWNERDRAW style will not respond to double click as normal buttons do. So the solution is as above. When the double click occurs, call the default window procedure of the button with WM_LBUTTONDOWN instead of the actual WM_LBUTTONDBLCLK.

Conclusion

The class provided can be used as a layer between CButton and the derived class for an owner draw button. It will help to avoid a lot of code and is pretty useful.

History

None.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 435098918-Oct-18 3:03
Member 435098918-Oct-18 3:03 
GeneralBorrowed double click snippet to suggest improvement to FooBtn Pin
Phil Outram12-Jan-10 6:19
Phil Outram12-Jan-10 6:19 
GeneralRe: Borrowed double click snippet to suggest improvement to FooBtn Pin
Nishad S12-Jan-10 13:29
Nishad S12-Jan-10 13:29 
Thank you for referring my article. Smile | :)

- ns ami -

GeneralCool! Pin
zaodt17-Nov-08 21:22
zaodt17-Nov-08 21:22 
GeneralRe: Cool! Pin
Nishad S17-Nov-08 21:45
Nishad S17-Nov-08 21:45 

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.