Home

MFC Topics: Menu Fundamentals

 

Introduction to the Main Menu

A menu is a list of actions the user can perform on an application. The actions are presented in one or more groups. There are broad categories of menus: the main menu and the context menu.

A main menu, also called a top-level menu, displays categories of menu items using a range of items called a menu bar:

 

When the user clicks an item of the menu bar, the item clicked opens its list:

After a list has been displayed, the user can then use an item from the list. Each item of the list is primarily a word or a group of words on a line. Different menu items are used for different reasons. For example, some menu items simply display a word or a group of words. Some other items display a check mark. This indicates that the item toggles the availability or disappearance of an object.

When a menu item is only meant to lead to a sub-menu, such a menu item is called a popup menu. There are two types of popup menus. If the menu displays on top of a window, which is the type of menu under the title bar, the word on top, which represents a category of menu, is a popup menu. If a menu item is equipped with an arrow in its right , which means the menu item has a submenu, such a menu item is also a popup menu. Popup menus are used only to represent a submenu. No inherent action is produced by clicking them, except that, when placed on top, such menu items allow opening the submenu.

To create menus that belong to a group, menu items are separated by a horizontal line called a separator. Separators are created differently in MSVC 6 and MSVC 7.

Practical Learning Practical Learning: Introducing Menus

  1. Start Microsoft Visual Studio or Visual C++ and create a Win32 Project named DepartmentStore1
  2. Click OK
  3. Create it as an Empty Project and click Finish
  4. On the main menu, click Project -> DepartmentStore1 Properties…
  5. Click Configuration Properties
  6. In the Use of MFC combo box of the right section, select Use MFC in a Shared DLL and click OK
  7. To create a header file, on the main menu, click Project -> Add New Item…
  8. In the Templates section of the dialog box, click Header File (.h)
  9. Set the Name to stdafx
  10. Click Add
  11. In the empty document, type #include <afxwin.h>
  12. To create a source file, on the main menu, click Project -> Add New Item…
  13. In the Templates section of the dialog box, click C++ File (.cpp)
  14. Set the Name to stdafx and click Add
  15. In the empty file, type #include “stdafx.h” and press Enter
  16. Add a new header file named MainFrm and, in it, type:
     
    #include "stdafx.h"
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame();
    	virtual ~CMainFrame();
    };
  17. Add a new source file named MainFrm and type the following in it:
     
    #include "MainFrm.h"
    
    CMainFrame::CMainFrame()
    {
    	Create(NULL,
    	TEXT("Department Store"),
    	WS_OVERLAPPEDWINDOW,
    	CRect(200, 120, 640, 400));
    }
    
    CMainFrame::~CMainFrame()
    {
    }
  18. Add a new header file named Exercise and, in it, type:
     
    #include "stdafx.h"
    
    class CExerciseApp: public CWinApp
    {
    public:
    	BOOL InitInstance();
    };
  19. Add a new source file named Exercise and type the following in it:
     
    #include "Exercise.h"
    #include "MainFrm.h"
    
    BOOL CExerciseApp::InitInstance()
    {
    	m_pMainWnd = new CMainFrame;
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    
    	return TRUE;
    }
    
    CExerciseApp theApp;
  20. Execute the application to test it

Menu Creation

There are two main ways you can create a main menu: Using a resource file or programmatically creating the menu items. You can create a resource file that has the .rc extension. The menu is created as text. If you create the file manually, you must also remember to create or edit the resource.h file in order to specify an identifier for each menu. The alternative, which we will use, is to "visually" create the menu in Visual Studio. When doing this, the studio itself would update the resource.h file as items are added or removed.

To visually create a menu, first add a resource of type Menu using the Add Resource dialog box. The MFC library implements a Windows menu, from the Win32’s HMENU class, through the CMenu class. Based on this, if you want to programmatically create a menu, you can start by declaring a CMenu variable. Here is an example:

#include <afxwin.h>

class CExerciseApp : public CWinApp
{
public:
	virtual BOOL InitInstance();
};

class CMainFrame : public CFrameWnd
{
public:
	CMainFrame();

private:
	CMenu m_wndMainMenu;
};

CMainFrame::CMainFrame()
{
	Create(NULL, "Menus Fundamentals");
}

BOOL CExerciseApp::InitInstance()
{
	m_pMainWnd = new CMainFrame;
	m_pMainWnd->ShowWindow(SW_NORMAL);

	return TRUE;
}

CExerciseApp theApp;

After declaring the variable, to indicate that you intend to create a menu, you must first call the CMenu::CreateMenu() method. Its syntax is:

BOOL CreateMenu();

Here is an example:

CMainFrame::CMainFrame()
{
	Create(NULL, "Menus Fundamentals");

	this->m_wndMainMenu.CreateMenu();
}

Just in case something might go wrong, the MFC provides the VERIFY macro that you can use to make sure that the menu was rightly initialized. It can be used as follows: 

CMainFrame::CMainFrame()
{
	Create(NULL, "Menus Fundamentals");

	VERIFY(this->m_wndMainMenu.CreateMenu());
}

After declaring the variable and calling CreateMenu(), you can start defining the characteristics of the menu. We will review the various characteristics in the next sections.

Practical Learning Practical Learning: Creating a Main Menu Visually

  1. On the main menu, click View -> Resource View and again, on the main menu, click Project -> Add Resource...
  2. On the Add Resource dialog box, double-click Menu
  3. In the Resource View, click IDR_MENU1 to select it
  4. In the Properties window, click ID, type IDR_FIRST and press Enter

Using a Menu

After creating a menu, before using it, you should associate it with a window frame that will carry it and present it to the user. To associate a menu with a window, you have various options. If you are using the CFrameWnd::Create() method to create the window, you can specify the name of the menu using the lpszMenuName argument:

virtual BOOL Create(
	LPCTSTR lpszClassName,
	LPCTSTR lpszWindowName,
	DWORD dwStyle = WS_OVERLAPPEDWINDOW,
	const RECT& rect = rectDefault,
	CWnd* pParentWnd = NULL,
	LPCTSTR lpszMenuName = NULL,
	DWORD dwExStyle = 0,
	CCreateContext* pContext = NULL 
);

Here is an example:

class CMainFrame : public CFrameWnd
{
public:
	CMainFrame()
	{
		Create(NULL, "Resources Fundamentals",
			WS_OVERLAPPEDWINDOW, CRect(200, 120, 640, 400),
			NULL,
			MAKEINTRESOURCE(IDR_MAINFRAME));
	}
};

If you are programmatically creating the menu using a CMenu object, to assign it to a frame, you can call the CWnd::SetMenu() method. Its syntax is:

BOOL SetMenu(CMenu* pMenu);

Here is an example:

CMainFrame::CMainFrame()
{
	Create(NULL, "Menus Fundamentals");

	VERIFY(this->m_wndMainMenu.CreateMenu());

	// Do whatever here

	this->SetMenu(&m_wndMainMenu);
}

If a window already has a menu and you want to get a reference to that menu, you can call its CWnd::GetMenu() method. Its syntax is:

CMenu *GetMenu() const;

When using this method, if the window that calls it doesn’t have a menu, this method returns NULL. Otherwise, this method returns a pointer to the CMenu object of the window that called it.

As stated already, The CMenu class is the MFC’s implementation of the HMENU handle. To get a handle to an existing CMenu object of an application, you can access the value of the CMenu::m_hMenu property, which is of type HMENU.

Practical Learning Practical Learning: Associating a Main Menu With a Window Frame

  1. Access the MainFrm.h file and declare a private pointer to CMenu as follows:
     
    #include "stdafx.h"
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame();
    	virtual ~CMainFrame();
    
    private:
    	CMenu *pCurrentMenu;
    };
  2. To associate the new menu with the frame, access the MainFrm.cpp file and change it as follows:
     
    #include "MainFrm.h"
    
    CMainFrame::CMainFrame()
    {
    	Create(NULL,
    		TEXT("Department Store"),
    		WS_OVERLAPPEDWINDOW,
    		CRect(200, 120, 640, 400));
    
    	// Dynamically create a menu... 
    	pCurrentMenu = new CMenu;
    	// ... using the menu resource we will create
    	pCurrentMenu->LoadMenuW(MAKEINTRESOURCE(IDR_FIRST));
    	// Assign the menu menu to the frame of the current application
    	SetMenu(pCurrentMenu);
    	// Draw the menu on the frame (this is not required 
    	// if this is the only time we will create a menu)
    	DrawMenuBar();
    }
    
    CMainFrame::~CMainFrame()
    {
    
    }
  3. Save the file

Menu Message Processing

As introduced earlier, a menu is primarily a list of actions that can be performed on an application. The actions are generated when the user positions the mouse on a menu item or when one of these items is clicked. If the user clicks an item such as File on the main menu, the menu item generates a WM_INITMENUPOPUP message. To get the program ready to process these messages, in the previous lesson, we saw that you should create a message map. Here is an example:

class CMainFrame : public CFrameWnd
{
public:
	CMainFrame()
	{
		Create(NULL, "Menus Fundamentals");
	}

	DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

END_MESSAGE_MAP()

BOOL CExoApp::InitInstance()
{
	. . .
}

If the MFC doesn’t provide a default function that processes your type of message, you should first implement the event that will process the message. Here is an example:

class CMainFrame : public CFrameWnd
{
public:
	CMainFrame()
	{
		Create(NULL, "Menus Fundamentals");
	}

	afx_msg void EndThisApplication();
	DECLARE_MESSAGE_MAP()
};

. . .

void CMainFrame::EndThisApplication()
{
	PostQuitMessage(0);
}

Once you have defined the method that will process the message, you can map it to a resource symbol in your message map section using the ON_COMMAND macro. Once this has been done, the application can process the message.

Practical Learning Practical Learning: Processing a Menu Message

  1. Access the MainFrm.h header file. To create an event that would process a message, change the file as follows:
     
    #include "stdafx.h"
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame();
    	virtual ~CMainFrame();
    
    	DECLARE_MESSAGE_MAP()
    
    private:
    	CMenu *pCurrentMenu;
    };
  2. Access the MainFrm.cpp source file and change it as follows:
     
    #include "MainFrm.h"
    
    CMainFrame::CMainFrame()
    {
    	. . .
    }
    
    CMainFrame::~CMainFrame()
    {
    
    }
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    
    END_MESSAGE_MAP()
  3. Save all
 

Home Copyright © 2006-2007 FunctionX, Inc. Next