Control Specific Context Menus

Apr 12, 2008
This article was written back when Visual Studio 6 was new. As such, I cannot guarantee that the content of this article still applies in modern Windows environments.

Context menus (or "right-click popup" menus) come in two flavors: application-wide or control-specific. This article focuses on the latter. If you are interested in application-wide menus, be sure to check out my article on that very subject.

Adding the Menu Resource

The first step in creating a context menu is simple: use the Visual Studio resource editor to create the menu you wish to display. Make sure that you give it a unique ID; I will use the value IDR_POPUP_MENU for this example. Add to the menu the various menu items that you want to include. Note that your context menu should only have one top-level item (under which all other menu items will be placed). The caption for this top-level item can be whatever you like since the user will never see it. If you are mapping menu items in this context menu to commands that already exist in the program (as is likely), make sure that you give each menu item the appropriate ID. For example, if the ID to my "Open File" command in my main application menu is ID_FILE_OPEN, I would give that same ID to the corresponding item in my context menu. If you aren't mapping commands, simply add any message handlers as normal.

Displaying the Menu

After you create the menu resource, we need to write the code that's responsible for showing the menu when the user right-clicks a specific control. For this example, I will assume that the control we are adding a menu to is a CListCtrl. Add the NM_RCLICK event handler to your list control, and edit the resulting handler method to look like the following:

void CYourDlg::OnRclickYourList(NMHDR* pNMHDR, LRESULT* pResult)
{
    CPoint point;
    GetCursorPos(&point);

    CMenu mnuTop;
    mnuTop.LoadMenu(IDR_POPUP_MENU);

    CMenu* pPopup = mnuTop.GetSubMenu(0);
    ASSERT_VALID(pPopup);

    pPopup->TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON |
        TPM_LEFTALIGN, point.x, point.y, AfxGetMainWnd(), NULL);

    *pResult = 0;
}

Understanding the Code

Let's examine this code so that we know exactly what's going on. We first create a CPoint object so that we can store the location of the mouse when the user clicks the right mouse button. Since the message is only fired when the user clicks within the list control, we can simply use a call to the GetCursorPos() method to get the mouse's current screen coordinates. We then create a menu object and attach the menu resource we created earlier to it. The parameter to the LoadMenu() method is simply the unique ID that we assigned to our menu.

Next, we set up a pointer to a menu object (this is what will actually control the popup menu). The pointer gets assigned to the return value of the GetSubMenu() method. The parameter that is passed here is the zero-based index of the submenu that will be used as the popup menu. Since our menu resource has only one top-level item, we need only to pass a parameter value of zero.

We finally use the TrackPopupMenu() method to create and draw the menu itself. The first parameter sets a screen position flag and a mouse button flag. As you can see from the flags I pass in, I allow the user to select menu items with either the left or right mouse buttons (which are the only two choices), and I align the left of the menu with the coordinate specified by the x parameter.

The next parameter is indeed that x value, which specifies the horizontal screen coordinate where the popup menu should appear. Likewise, they y (vertical) parameter follows the x value. In both cases, we use the CPoint object's values that we got from our call to GetCursorPos().

The fourth parameter identifies the window that owns this popup menu. This window will receive all the messages sent from the menu, so we pass AfxGetMainWnd() in order to get the application's main window object.

The final parameter is either a RECT structure or CRect object that specifies a rectangular area in which the user can click without dismissing the popup menu. If you just leave this set to NULL, things will work properly (i.e., clicking outside of the menu will dismiss it).

No comments (yet!)

Leave a Comment

Ignore this field:
Never displayed
Leave this blank:
Optional; will not be indexed
Ignore this field:
Both Markdown and a limited set of HTML tags are supported
Leave this empty: