Click here to Skip to main content
12,446,296 members (53,558 online)
Click here to Skip to main content
Add your own
alternative version

Stats

93.9K views
1.8K downloads
45 bookmarked
Posted

Owner-drawn context menu in WTL

, 24 Apr 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
An article explaining how to create an owner-drawn context menu.

WTL Context Menu

Introduction

I was looking for a code to implement an owner-drawn context menu in WTL, but could not find any; everything I found would modify the behavior of the CCommandBarCtrl, and could not be used in a context menu displayed by, let's say, an edit control.

In this article, I’ll show you how to implement an owner-drawn context menu, and how to add cool-looking menus to your application real easy, using my class CCoolContextMenu.

Implementation

In order to make an item an owner-drawn item, you must create a new menu item, or modify an existing one by setting the MFT_OWNERDRAW menu flag.

You can use the InsertMenuItem or SetMenuItemInfo functions to set or change information about a menu item. When calling these two functions, you must specify a pointer to a MENUITEMINFO structure, which specifies the properties of the menu item.

You need to specify the MFT_OWNERDRAW value for the fType member, for an item to become an owner-drawn item. You can also associate an application-defined value, which is called item data, with each menu item. The CCoolContextMenu class defines the MenuItemData structure that contains the information used to draw a menu item. The application uses the dwItemData member to store a pointer to this structure.

The MenuItemData structure is sent to the menu's owner window with the WM_MEASUREITEM and WM_DRAWITEM messages. The GetMenuItemInfo function is used to retrieve the item data for a menu at any time.

LRESULT InitMenuPopupHandler(UINT uMsg, WPARAM wParam, 
                             LPARAM lParam, BOOL& bHandled)
{
    // System menu, do nothing
    if ((BOOL)HIWORD(lParam))   
    {
        bHandled = FALSE;
        return 1;
    }

    CMenuHandle menuPopup = (HMENU)wParam;
    ATLASSERT(menuPopup.m_hMenu != NULL);

    TCHAR szString[MAX_MENU_ITEM_TEXT_LENGTH];
    BOOL bRet = FALSE;

    for (int i = 0; i < menuPopup.GetMenuItemCount(); i++)
    {
        CMenuItemInfo mii;
        mii.cch = MAX_MENU_ITEM_TEXT_LENGTH;
        mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | 
                    MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;
        mii.dwTypeData = szString;
        bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);
        ATLASSERT(bRet);

        if (!(mii.fType & MFT_OWNERDRAW))
        // not already an ownerdraw item
        {
            MenuItemData * pMI = new MenuItemData;
            ATLASSERT(pMI != NULL);

            if (pMI)
            {
                // Make this menu item an owner-drawn
                mii.fType |= MFT_OWNERDRAW;

                pMI->fType = mii.fType;
                pMI->fState = mii.fState;

                // Associate an image with a menu item
                static_cast<T*>(this)->AssociateImage(mii, pMI);

                pMI->lpstrText = new TCHAR[lstrlen(szString) + 1];
                ATLASSERT(pMI->lpstrText != NULL);

                if (pMI->lpstrText != NULL)
                    lstrcpy(pMI->lpstrText, szString);
                mii.dwItemData = (ULONG_PTR)pMI;

                bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);
                ATLASSERT(bRet);
            }
        }
    }

    // Add it to the list
    m_stackMenuHandle.Push(menuPopup.m_hMenu);
    
    return 0;
}

Internally, CCoolContextMenu implements WM_MEASUREITEM, WM_DRAWITEM, WM_INITMENUPOPUP, and WM_MENUSELECT messages so you do not have to worry about anything.

Using the code

To use the CCoolContextMenu class, all you have to do is to derive your class from CCoolContextMenu and follow the next few steps:

class CCoolEdit : public CWindowImpl<CCoolEdit, CRichEditCtrl>,
                  public CRichEditCommands<CCoolEdit>,
                  public CCoolContextMenu<CCoolEdit>

In the message map, use CHAIN_MSG_MAP to redirect messages to CCoolContextMenu's message map:

BEGIN_MSG_MAP(CCoolEdit)
    ...
    CHAIN_MSG_MAP(CCoolContextMenu<CCoolEdit>)
END_MSG_MAP()

In the OnInitDialog() function of your dialog class, or in the OnCreate() function of the window class, call the GetSystemSettings() method of CCoolContextMenu:

LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, 
                     LPARAM lParam, BOOL& bHandled)
{
    ...
    GetSystemSettings();
    ...
}

But wait! What about images? Don't worry, just create the image list and implement the AssociateImage(CMenuItemInfo& mii, MenuItemData * pMI) function in your CCoolContextMenu derived class:

void AssociateImage(CMenuItemInfo& mii, MenuItemData * pMI)
{
    switch (mii.wID)
    {
    case ID_EDIT_UNDO:
        pMI->iImage = 17;
        break;
    case ID_EDIT_CUT:
        pMI->iImage = 3;
        break;
    case ID_EDIT_COPY:
        pMI->iImage = 4;
        break;
    case ID_EDIT_PASTE:
        pMI->iImage = 5;
        break;
    case ID_EDIT_CLEAR:
        pMI->iImage = 20;
        break;
    default:
        pMI->iImage = -1;
        break;
    }
}

Conclusion

CCoolContextMenu allows you to add nice looking context menus to your application with just a few lines of code; and by combining my code with Jean-Michel's, your windows will look completely different.

My Thanks To

History

  • March 13, 2006 - Initial release.
  • March 15, 2006 - Put a message map in the CCoolContextMenu class. Thanks to Jörgen Sigvardsson for suggesting it.
  • April 24, 2006 - Added a default implementation of the AssociateImage function to the CCoolContextMenu class.

Disclaimer

THIS SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT ANY WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO RESPONSIBILITIES FOR POSSIBLE DAMAGES CAN BE TAKEN. THE USER MUST ASSUME THE ENTIRE RISK OF USING THIS SOFTWARE.

License

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

Share

About the Author

Igor Vigdorchik
Web Developer
United States United States
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionCBoldDC bold(*pDC, (lpDrawItemStruct->itemState & ODS_DEFAULT) != 0); Pin
kuibing24-Jun-11 15:24
memberkuibing24-Jun-11 15:24 
GeneralNice work - but you undersold it! Pin
John Hind16-Sep-10 1:01
memberJohn Hind16-Sep-10 1:01 
GeneralA few bugs and opportunities: Pin
John Hind29-Sep-10 0:10
memberJohn Hind29-Sep-10 0:10 
GeneralRe: A few bugs and opportunities: Pin
Igor Vigdorchik29-Sep-10 14:03
memberIgor Vigdorchik29-Sep-10 14:03 
GeneralRe: A few bugs and opportunities: Pin
John Hind29-Sep-10 22:56
memberJohn Hind29-Sep-10 22:56 
GeneralRe: A few bugs and opportunities: Pin
Igor Vigdorchik30-Sep-10 14:27
memberIgor Vigdorchik30-Sep-10 14:27 
GeneralMy revised version: Pin
John Hind29-Sep-10 23:00
memberJohn Hind29-Sep-10 23:00 
GeneralRe: My revised version: Pin
phoenicyan3-Jan-15 8:49
memberphoenicyan3-Jan-15 8:49 
GeneralMenu not drawn second time Pin
rajas23-Feb-09 20:32
memberrajas23-Feb-09 20:32 
GeneralRe: Menu not drawn second time Pin
Igor Vigdorchik24-Feb-09 14:12
memberIgor Vigdorchik24-Feb-09 14:12 
GeneralRe: Menu not drawn second time Pin
rajas4-Mar-09 19:04
memberrajas4-Mar-09 19:04 
GeneralSuggestion... Pin
Oliver Jennert17-Feb-09 0:42
memberOliver Jennert17-Feb-09 0:42 
GeneralRe: Suggestion... Pin
Igor Vigdorchik18-Feb-09 15:03
memberIgor Vigdorchik18-Feb-09 15:03 
GeneralThanks man! [modified] Pin
machnotrix26-May-08 1:28
membermachnotrix26-May-08 1:28 
GeneralRe: Thanks man! Pin
Igor Vigdorchik26-May-08 5:39
memberIgor Vigdorchik26-May-08 5:39 
GeneralVery Nice code, but small question! Pin
SeekTruth3-Apr-08 23:25
memberSeekTruth3-Apr-08 23:25 
GeneralRe: Very Nice code, but small question! Pin
Igor Vigdorchik4-Apr-08 6:47
memberIgor Vigdorchik4-Apr-08 6:47 
GeneralSmall fix Pin
Val Salamakha18-May-07 15:24
memberVal Salamakha18-May-07 15:24 
GeneralRe: Small fix [modified] Pin
Igor Vigdorchik18-May-07 15:41
memberIgor Vigdorchik18-May-07 15:41 
GeneralRe: Small fix Pin
Val Salamakha18-May-07 20:07
memberVal Salamakha18-May-07 20:07 
GeneralExcellent piece of code Pin
digitally_urs21-Dec-06 21:00
memberdigitally_urs21-Dec-06 21:00 
QuestionProject Help Wanted Pin
Prafulla Tekawade11-Sep-06 20:46
memberPrafulla Tekawade11-Sep-06 20:46 
GeneralFound a bug Pin
bobnob20-Jun-06 15:12
memberbobnob20-Jun-06 15:12 
GeneralRe: Found a bug Pin
bobnob20-Jun-06 15:19
memberbobnob20-Jun-06 15:19 
QuestionGood work (1 question) Pin
sergytmp4-Jun-06 22:15
membersergytmp4-Jun-06 22:15 
AnswerRe: Good work (1 question) Pin
Igor Vigdorchik5-Jun-06 4:32
memberIgor Vigdorchik5-Jun-06 4:32 
GeneralRe: Good work (1 question) Pin
sergytmp6-Jun-06 5:52
membersergytmp6-Jun-06 5:52 
GeneralRe: Good work (1 question) Pin
Igor Vigdorchik6-Jun-06 7:03
memberIgor Vigdorchik6-Jun-06 7:03 
GeneralA question Pin
cozy dude30-May-06 4:09
membercozy dude30-May-06 4:09 
GeneralRe: A question Pin
Igor Vigdorchik30-May-06 7:37
memberIgor Vigdorchik30-May-06 7:37 
GeneralRe: A question Pin
cozy dude31-May-06 1:43
membercozy dude31-May-06 1:43 
GeneralRe: A question Pin
Igor Vigdorchik31-May-06 5:04
memberIgor Vigdorchik31-May-06 5:04 
GeneralRe: A question Pin
cozy dude7-Jun-06 5:05
membercozy dude7-Jun-06 5:05 
GeneralRe: A question Pin
Igor Vigdorchik7-Jun-06 13:03
memberIgor Vigdorchik7-Jun-06 13:03 
GeneralRe: A question Pin
Anton Bredikhin26-May-08 5:04
memberAnton Bredikhin26-May-08 5:04 
GeneralRe: A question Pin
Anton Bredikhin26-May-08 6:07
memberAnton Bredikhin26-May-08 6:07 
GeneralGood... Pin
JaeWook Choi28-Mar-06 5:30
memberJaeWook Choi28-Mar-06 5:30 
GeneralRe: Good... Pin
Igor Vigdorchik28-Mar-06 6:27
memberIgor Vigdorchik28-Mar-06 6:27 
GeneralWhy not... Pin
Jörgen Sigvardsson14-Mar-06 10:15
memberJörgen Sigvardsson14-Mar-06 10:15 
GeneralRe: Why not... Pin
Igor Vigdorchik14-Mar-06 11:17
memberIgor Vigdorchik14-Mar-06 11:17 
GeneralRe: Why not... Pin
Jörgen Sigvardsson14-Mar-06 11:46
memberJörgen Sigvardsson14-Mar-06 11:46 
GeneralRe: Why not... Pin
Igor Vigdorchik14-Mar-06 13:40
memberIgor Vigdorchik14-Mar-06 13:40 

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.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.160811.3 | Last Updated 24 Apr 2006
Article Copyright 2006 by Igor Vigdorchik
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid