Home

MFC Topics: Characteristics of Menu Items

 

Introduction

Many applications rely on menus to assist the user with their interaction with the computer. To fully support this interaction, Microsoft Windows provides the menus with various characteristics meant to serve different purposes. Based on this, menus have such behaviors and properties as alignment, radio buttons, check boxes, grouping, etc.

A Popup Menu

A main menu is made of categories of items. A category displays as a list when the user clicks its top item:

An item in the top-level of a menu is referred to as popup. To visually create a popup menu, you can click the Menu node from the Add Resource dialog box; click Type Here and type a string for the menu category.

To programmatically create a popup menu, call the CMenu::AppendMenu() method. Its comes in two versions whose syntaxes are:

BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0,
		LPCTSTR lpszNewItem = NULL);
BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, const CBitmap* pBmp);

If you are creating a simple menu item that will display by itself, you can (must) set the first argument as MF_STRING. The second argument can be a ResourceID name as we reviewed them earlier. If you are creating a simple menu item, you can pass this argument as 0 or NULL. The third argument can be a string if you want to display a simple menu item. 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");

	VERIFY(this->m_wndMainMenu.CreateMenu());
	this->m_wndMainMenu.AppendMenu(MF_STRING, NULL, "Smell");
	this->SetMenu(&m_wndMainMenu);
}

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

	return TRUE;
}

CExerciseApp theApp;

This would produce:

If you want to create a real popup menu that display on a top-level and holds its own list of menu items, you can first create a CMenu object that will holds the menu items under the popup. Such a popup menu starts like the menu item we created above. Here is an example:

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

private:
	CMenu m_wndMainMenu;
	CMenu m_wndFileMenu;
};

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

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

	this->m_wndMainMenu.AppendMenu(MF_STRING, NULL, "File");
	this->SetMenu(&m_wndMainMenu);
}

After initializing the popup menu, you can call the CMenu::AppendMenu() for each menu item that you want to display under the popup. In this case, you should pass the first argument as MF_STRING, the second argument with a constant number that can be the name of a resource symbol we introduced earlier, and the last argument can be the string that would display in the menu item. Here are three examples:

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

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

	this->m_wndFileMenu.AppendMenu(MF_STRING, 22001, "New");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22002, "Open");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22003, "Save");

	this->SetMenu(&m_wndMainMenu);
}

After defining the menu items that would display under the top-level menu, you can add assign the group to the popup menu. To do this, you can call the CMenu::AppendMenu() method. This time, the first argument would be passed as MF_POPUP, the second argument must be a reference to the CMenu object that holds the popup menu, and the last argument should be the string that will represent the popup menu. This would be done as follows:

#include <afxwin.h>

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

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

private:
	CMenu m_wndMainMenu;
	CMenu m_wndFileMenu;
};

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

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

	this->m_wndFileMenu.AppendMenu(MF_STRING, 22001, "New");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22002, "Open");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22003, "Save");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndFileMenu.m_hMenu),
			"File");
	this->SetMenu(&m_wndMainMenu);
}

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

	return TRUE;
}

CExerciseApp theApp;

This would produce:

Just as we created this one popup menu, you can create as many menu items as necessary. Here are examples:

#include <afxwin.h>

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

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

private:
	CMenu m_wndMainMenu;
	CMenu m_wndFileMenu;
	CMenu m_wndEditMenu;
	CMenu m_wndHelpMenu;
};

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

	VERIFY(this->m_wndMainMenu.CreateMenu());
	VERIFY(this->m_wndFileMenu.CreateMenu());
	VERIFY(this->m_wndEditMenu.CreateMenu());
	VERIFY(this->m_wndHelpMenu.CreateMenu());

	this->m_wndFileMenu.AppendMenu(MF_STRING, 22001, "New");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22002, "Open");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22003, "Save");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndFileMenu.m_hMenu),
			"File");

	this->m_wndEditMenu.AppendMenu(MF_STRING, 22004, "Cut");
	this->m_wndEditMenu.AppendMenu(MF_STRING, 22005, "Copy");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndEditMenu.m_hMenu),
			"Edit");

	this->m_wndHelpMenu.AppendMenu(MF_STRING, 22005,
					"About this Application");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndHelpMenu.m_hMenu),
			"Help");

	this->SetMenu(&m_wndMainMenu);
}

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

	return TRUE;
}

CExerciseApp theApp;

This would produce:

 

Practical Learning Practical Learning: Creating a Main Menu

  1. In the Resource View, double-click IDR_MAINFRAME to get back to the menu.
    In the main window, click the top box, type File and press Enter
  2. Click the item under File. Type New Order
  3. In the Properties window, click ID and set its value to IDM_FILE_NEW
  4. Press Enter
  5. In the Type Here box under the New string, type Open Order
  6. In the Properties window, click ID and set its value to IDM_FILE_OPEN
  7. Press Enter
  8. In the Type Here box under the New string, type Exit
  9. In the Properties window, click ID and set its value to IDM_FILE_EXIT
  10. Press Enter
  11. Access the stdafx.h header file and, under the existing #include line, type
     
    #include “resource.h”
  12. Access the MainFrm.h file and declare the following method:
     
    #include "stdafx.h"
    
    class CMainFrame : public CFrameWnd
    {
    public:
    	CMainFrame();
    	virtual ~CMainFrame();
    
    	afx_msg void Close();
    
    	DECLARE_MESSAGE_MAP()
    
    private:
    	CMenu *pCurrentMenu;
    };
  13. Access the MainFrm.cpp file and change it as follows:
     
    #include "MainFrm.h"
    
    CMainFrame::CMainFrame()
    {
    	. . .
    }
    
    CMainFrame::~CMainFrame()
    {
    
    }
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	ON_COMMAND(IDM_FILE_EXIT, Close)
    END_MESSAGE_MAP()
    
    void CMainFrame::Close()
    {
    	PostQuitMessage(WM_QUIT);
    }
  14. Execute the application to test it

Moving a Menu

While or after creating your menu, you may find out that a menu category is in the wrong sequence or a menu item is in the wrong position. You can visually move either a menu category or a menu item.

To menu a menu category, click an hold the mouse on it. Drag either left or right in the direction of your choice. As you are moving it, a short vertical line with double arrows will follow and guide you. Once the vertical line is positioned where you want the menu category to be, release the mouse.

To move a menu item, click and hold your mouse on it. Drag either up or down where you want to position it. While you are dragging, a horizontal line will guide you. Once the line is positioned where you want the menu item ot be, release the mouse. 

Menu Separators

A menu separator is a line that separates two groups of menu items. It can be used in two main ways. It can simply be used to set apart different groups, or, as we will see later on, it can assist with implementing the behavior of radio buttons in a menu.

If you are visually creating a menu, to create a separator, set the string of a menu item as – and press Enter. If you are programmatically creating a menu, to specify a separator, call the CMenu::AppendMenu() method. Pass the first argument as MF_SEPARATOR, the second as NULL, and the last argument as “-“. Here is an example:

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

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

	this->m_wndFileMenu.AppendMenu(MF_STRING, 22001, "New");
	this->m_wndFileMenu.AppendMenu(MF_SEPARATOR, NULL, "-");
	this->m_wndFileMenu.AppendMenu(MF_STRING | MF_DISABLED, 22004, "Exit");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndFileMenu.m_hMenu),
			"File");

	this->SetMenu(&m_wndMainMenu);
}

This would produce:

Practical Learning Practical Learning: Creating a Menu Separator

  1. In the Resource View, double-click IDR_FIRST. In the menu, click Exit
  2. Press Ins (or Insert depending on your keyboard
  3. Type – and press Enter
  4. Notice that a separator was added between Open and Exit.
    Save all

Menu Alignment

By default, when you create a popup menu item, it is aligned to the left. If it is the first group, it would be positioned to the left of the menu bar. If you add another popup menu, it would be positioned immediately to the right of the previous group. This alignment continues every time you add a new popup menu. This alignment is to the left of the menu bar. Microsoft Windows allows you to align one or more menu groups or menu items to the right. Based on this, if you create a first popup menu, instead of aligning it to the left, you may prefer to position it to the right of the menu bar. Here is what it would appear like:

To specify the alignment of a menu item, if you are visually creating the menu, set the Help property to True in the Properties window. If you are programmatically creating the menu, bitwise-OR the MF_HELP flag to the first argument. Based on this, the above menu was created as follows:

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

	VERIFY(this->m_wndMainMenu.CreateMenu());
	VERIFY(this->m_wndFileMenu.CreateMenu());
	VERIFY(this->m_wndEditMenu.CreateMenu());
	VERIFY(this->m_wndHelpMenu.CreateMenu());

	this->m_wndFileMenu.AppendMenu(MF_STRING, 22001, "New");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22002, "Open");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22003, "Save");
	this->m_wndMainMenu.AppendMenu(MF_POPUP | MF_HELP,
			reinterpret_cast<UINT_PTR>(this->m_wndFileMenu.m_hMenu),
			"File");
	this->SetMenu(&m_wndMainMenu);
}

You can also position one or more popup menus to the left and one or more popup menu items to the right of the menu bar. To do this, if you are visually creating the menu, set the desired menu item’s Help property to True. That popup menu item and all top-level menus positioned to the right of that menu would be positioned to the right. If you are programmatically creating a menu, you can bitwise-OR one popup menu. That popup menu and all top-level menu items created after it would be positioned to the right. 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;
	CMenu m_wndFileMenu;
	CMenu m_wndViewMenu;
	CMenu m_wndEditMenu;
	CMenu m_wndHelpMenu;
};

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

	VERIFY(this->m_wndMainMenu.CreateMenu());
	VERIFY(this->m_wndFileMenu.CreateMenu());
	VERIFY(this->m_wndViewMenu.CreateMenu());
	VERIFY(this->m_wndEditMenu.CreateMenu());
	VERIFY(this->m_wndHelpMenu.CreateMenu());

	this->m_wndFileMenu.AppendMenu(MF_STRING, 22001, "New");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22002, "Open");
	this->m_wndFileMenu.AppendMenu(MF_STRING, 22003, "Save");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndFileMenu.m_hMenu),
			"File");

	this->m_wndViewMenu.AppendMenu(MF_STRING, 22002, "Toolbar");
	this->m_wndViewMenu.AppendMenu(MF_STRING, 22003, "Status Bar");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndViewMenu.m_hMenu),
			"View");

	this->m_wndEditMenu.AppendMenu(MF_STRING, 22004, "Cut");
	this->m_wndEditMenu.AppendMenu(MF_STRING, 22005, "Copy");
	this->m_wndMainMenu.AppendMenu(MF_POPUP | MF_HELP,
			reinterpret_cast<UINT_PTR>(this->m_wndEditMenu.m_hMenu),
			"Edit");

	this->m_wndHelpMenu.AppendMenu(MF_STRING, 22005,
			"About this Application");
	this->m_wndMainMenu.AppendMenu(MF_POPUP,
			reinterpret_cast<UINT_PTR>(this->m_wndHelpMenu.m_hMenu),
			"Help");

	this->SetMenu(&m_wndMainMenu);
}

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

	return TRUE;
}

CExerciseApp theApp;

This would produce:

Practical Learning Practical Learning: Aligning a Menu

  1. On the menu, click File and click the box labeled Type Here on the right side of File
  2. Type Help and, in the Properties window, set its Help value to True
  3. Click the Type Here box under Help and type About…
  4. Save all 

The Position of a Menu Item

When we study menu maintenance, we will see that many routine operations require that you be able to locate a menu item before taking action. Locating an item is possible if you consider that the menus item are stored in a 0-based list.

Mnemonics

If you look at the menu of most applications, one letter on every menu is underlined allowing the users to access the menu without using the mouse. That menu should first receive focus, this is done by pressing Alt or F10, then eventually, the underlined letter of the menu that the user wants to access. For example, if you press Alt, then F now, the File menu will open. Get in the same good habit of accommodating your users. The mnemonics can be used anywhere in your application, including dialog boxes, combo boxes, check boxes, radio buttons, etc. So, get in the habit of using them. The ones on the menu will be used if the menu has focus (Alt or F10). The others are available anytime.

A mnemonic is created by using the ampersand & before the letter you judge appropriate. On the categories of a main menu, you should use a unique letter for each category Consider the main menu of Microsoft Visual Studio. Only one F letter is underlined on the whole main menu, only one E, only one V, etc. Programmers tend to consider the first letter of each top menu. If you get in a situation where two words start with the same letter, consider using the 2nd letter. For example, if you have one category with File and another category with Format, you can apply the first mnemonic on the F of File and use the o letter on Format.

Sometimes you will get in a situation where either you get confused because of so much menu to create, or too many items that need mnemonics. In any case you can ask Microsoft Visual Studio to help you identify double mnemonics. To do this, right-click a menu and select Check Mnemonics.

Shortcuts

A shortcut is an action, similar to that of a menu item, that can be performed by pressing one or a combination of keys. For example, to open the Start menu of Microsoft Windows, you can press Ctrl + Esc, to open the System menu of any application, press Alt + Space, to save a document on most (if not all) Microsoft applications, press Ctrl + S., etc. For a typical program, you should provide a shortcut to your users for most menu actions performed on your application. As a suggestion, observe other applications, such as a word processor. Many actions on such an application have shortcuts even when the shortcut is not listed. It allows people who like shortcuts to do their job faster, it also anticipates the situations when the mouse is behaving badly.

People who use Microsoft Windows and Microsoft software products are usually familiar with a lot of "universal" shortcuts such as Ctrl + C, Ctrl + V, Delete, etc. You can see some of these if you click File or Edit on the main menu. Those are shortcuts that are explicitly and readily available. Other shortcuts, though completely efficient, can also be made available.

The easiest way to let users know about the shortcuts is by displaying them on the menu. For example Ctrl+N, Ctrl+C, etc are already displayed on the menu. To provide a shortcut, append \t and the shortcut combination in the Caption of a menu item. 

Menu Prompts

The status bar can be used to display a message to the user about a menu item, like a small detail. Here is an example, on the main menu of Microsoft Visual Studio, click Projects followed by a menu item and look at the Status Bar. While the menu is still opened, move the mouse to another menu item and look at the Status Bar. When you have finished, press Esc twice to dismiss the menu.

To specify the message that would be displayed on the status bar, when designing the menu, click a menu item and, in the Properties window, type a string in the Prompt field.

 

Previous Copyright © 2006-2007 FunctionX, Inc. Next