Navigation Bar

04 November 2012

[ MFC ] - Display Context Menu On right button click using CMenu TrackPopupMenu


1.Introduction


In this article, we are going to create Main menu with four menu items in it. The last menu item is going to open a sub menu. The menu will be displayed when the mouse is right-clicked in the client area of the window and at the location of the mouse pointer.


2. About the sample


The below screenshot shows the application sample:



The sample is an SDI Application without document and view architecture support. The client area is marked in yellow border and when the mouse pointer is inside the client area of the window, the right client will display a pop-up menu.

Here we are creating the menu items at runtime and displaying the popup menu as shown in the screenshot.

The video given below shows default setting overridden for MFC SDI Application.



Video: Creating Project

3. Process WM_CONTEXTMENU

When the mouse is right clicked inside the client area of the window, the window will get a notification message WM_CONTEXTMENU. This message will come with the window in which the mouse is right clicked and pointer position in screen coordinate in which the mouse pointer lies when the click happened. This notification message will be used to display the popup menu.
The video given below shows providing the handler for the WM_CONTEXTMENU notification message. The notification is handled by the class CChildView.

Video: Adding Handler


In the video, you saw view class provides the handler for the notification message that we are discussing. The handler provided looks like below:
void CChildView::OnContextMenu(CWnd* pWnd, CPoint point)
Here, pWnd the pointer to the window in which the right client is done. The second param, point is cursor location in screen co-ordinate.

4. Display Context Menu by Handling OnContextMenu

The menu is created in side the handler provided for the WM_CONTEXTMENU.

1) First a CRect class declared to get the client window dimensions. Next, SubMenu and MainMenu instance of type CMenu is created.
//Sample 01: Declarations
CRect client_rect;
CMenu SubMenu, MainMenu;

2) We first get the client area of the window in client_rect structure. Then we convert this structure into Screen co-ordinate, which from the Top left of your monitor. We do this because the point parameter given to the handler as second argument is in screen co-ordinate.

//Sample 02: Get Mouse Click position and convert it to the Screen Co-ordinate
GetClientRect(&client_rect);
ClientToScreen(&client_rect);

3) We will display the popup context menu only when the mouse is right clicked inside the client area of the window. Therefore, we should check the mouse click position lies inside the client rectangle dimension. Note that as we get the mouse position in screen co-ordinate, so we converted the rectangle dimension client_rect into screen co-ordinate before doing the PtInrect check.

//Sample 03: Check the mouse pointer position is inside the client area
if( client_rect.PtInRect(point))
{

4) First, the Sub Menu for the context menu is created by calling the CreatePopupMenu function of the CMenu object. Then the menu items are added to it using the append menu function call.  The first parameter passed as MF_STRING says that we adding the string menu item. The second parameter is ID value that we give to the menu item. This Id will be used later when we need to process Command Message (Not covered in this article). The last parameter is display string of the menu item.

Once the Sub menu is created, we start creating the Main Menu. This menu is created the same way the sub menu is created. However, the last item on the Main menu is a sub menu that we already created. Note that we added the sub menu to this main menu; we passed the MF_POPUP as the first parameter to the function call AppendMenu. This will indicate the append menu that unlike the normal menu item the function should create the cascading menu for the menu item shown as Line Thickness.

//Sample 04: Create the sub Menu First
SubMenu.CreatePopupMenu();
SubMenu.AppendMenu(MF_STRING, 4001, _T("1"));
SubMenu.AppendMenu(MF_STRING, 4002, _T("2"));
SubMenu.AppendMenu(MF_STRING, 4003, _T("4"));
SubMenu.AppendMenu(MF_STRING, 4004, _T("8"));
//Sample 05:Create the Main Menu
MainMenu.CreatePopupMenu();
MainMenu.AppendMenu(MF_STRING, 4005, _T("Line"));
MainMenu.AppendMenu(MF_STRING, 4006, _T("Circle"));
MainMenu.AppendMenu(MF_STRING, 4007, _T("Polygon"));
MainMenu.AppendMenu(MF_POPUP, (UINT)SubMenu.GetSafeHmenu(), _T("Line Thickness"));

5) Finally, we call TrackPopupMenu to display the context that we created at runtime. The first parameter TPM_LEFTALIGN tells that the displayed popup menu should left align with the cursor location. The x and y position tells where we want to display the MainMenu as popup menu.

//Sample 06: Display the Popup Menu
MainMenu.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this);
The video given below shows the sample in action.

Video: Running the Sample


Source Code: Download