Teach Yourself Visual C++ 6 in 21 Days

Previous chapterNext chapterContents


- 6 -
Creating Menus for Your Application



Most Windows applications use pull-down menus to provide the user a number of functions without having to provide buttons on the window. This enables you to provide your users a large amount of functionality while preserving most of your valuable screen real estate for other stuff.

Today you will learn

Menus

Back when the first computer terminals were introduced and users began using computer software, even on large mainframe systems software developers found the need to provide the users with some sort of menu of the functions that the computer could perform. These early menus were crude by today's standards and were difficult to use and navigate. Menus have progressed since then; they've become standardized in how they are used and easy to learn.

The software designers that first came up with the idea of a graphical user interface (GUI) planned to make computer systems and applications easier to learn by making everything behave in a consistent manner. Menus used for selecting application functionality were one part of the GUI design that could be more easily learned if they all worked the same. As a result, a number of standard menu styles were developed.

Menu Styles

The first menu styles that were standardized are the pull-down and cascading menus. These are the menus with the categories all listed in a row across the top of the application window. If you select one of the categories, a menu drops down below the category, with a number of menu entries that can be selected to trigger various functions in the application.

A variation on this menu style is the cascading menu, which has another submenu that opens to the right of a menu entry. This submenu is similar to the pull-down menu, with a number of entries that trigger application functions. The menu designers placed no limit on how many cascading menus can be strung together, but it quickly became clear to most developers that more than two cascading levels is a little unwieldy.

Eventually, a third style of menu was developed, called a pop-up or context menu--a menu that pops up in the middle of the application area, floating freely above the application work area. This is also called a context menu because the specific menu that pops up is dependent on the selected object or workspace area where the cursor or mouse pointer is.

Keyboard Shortcut-Enabling Menus

When users began working with keyboard-intensive applications, such as word processors, it was discovered that taking your hands off the keyboard to use the mouse to make menu selections dramatically reduced productivity. Software designers decided that they needed to add keyboard shortcuts for the various menu entries (especially the most frequently used menu options). For this reason, keyboard shortcuts (accelerators) and hotkeys were added.

Hotkeys are letters that are underlined in each menu entry. If you press the Alt key with the underlined letter, you can select the menu entry that contains the underlined letter. This is a means of navigating application menus without taking your hands off the keyboard.

For more advanced users, application designers added keyboard shortcuts, or accelerators. An accelerator is a single key combination that you can press to trigger an application function instead of having to navigate through the application menus. This allows advanced users to avoid the overhead of using menus for the most common application functions. To enable users to learn what accelerators are available in an application, the key combination is placed on the menu entry that it can be used to replace, positioned at the right edge of the menu window.

Menu Standards and Conventions

Although there are no standards in how menus are designed, there are a number of conventions for how they are designed and organized. All these conventions are available in Windows Interface Guidelines for Software Design, published by Microsoft for use by Windows software developers. The purpose of this publication is to facilitate the development of consistent application behaviors, which will help accomplish one of the primary goals behind the development of GUI systems. The conventions are as follows:

Designing Menus

Menus are defined as a resource in Visual C++ applications. Because they are a resource, you can design menus in the Visual C++ editor through the Resource View tab on the workspace pane. When you first create a dialog-style application, there won't be a menu folder in the resource tree, but you can change that.


NOTE: Various aspects of Windows applications are considered to be resources, including window layouts, menus, toolbars, images, text strings, accelerators, and so on. All these features are organized in what is known as a resource file, which is used by the Visual C++ compiler to create these objects from their definitions. The resource file is a text file with an .rc filename extension and contains a textual description of all the various objects, including IDs, captions, dimensions, and so on.
Some resources, such as images and sounds, cannot be described in text, but have to be stored in a binary format. These resources are stored in individual files, with the filenames and locations included in the resource file.

Creating a Menu

Creating a menu is not difficult. You will follow several steps:

1. Create the application that will house the menu.

2. Add a menu resource to your project.

3. Customize the menu resource to include the menu items for your application.

4. Add functionality to your menu by connecting routines to your menu items.

Creating the Application

For the example in this chapter, you will create a simple dialog-style application that contains a single button and a menu. To create your application, do the following:

1. Create a new MFC AppWizard application, naming the project Menus.

2. Select the default AppWizard settings on all screens. For the dialog title, enter Menus.

3. When the AppWizard has generated your application shell, delete all the controls from the dialog.

4. Add a single button to the dialog. Name the button IDC_EXIT, and specify the caption as E&xit.

5. Add a function to the button using the Class Wizard. Change the code in this function to call OnOK. Remember, the OnOK function causes the application to close.


NOTE: If you don't remember how to add the OnOK function, review the section "Closing the Application" on Day 2, "Using Controls in Your Application," for an example.

Adding and Customizing a Menu

Now that you have the basic application built, it's time to start creating a menu for the application. To create a menu, you will first add a menu resource to your project. When you add the resource, Visual C++ automatically invokes the Menu Designer, which allows you to customize the menu. The following steps show you how to add and customize a menu:

1. Select the Resource View tab in the workspace pane.

2. Select the project resources folder at the top of the tree; in your example, this is Menus.

3. Right-click the mouse to bring up a pop-up menu.

4. Select Insert from the pop-up menu.

5. In the Insert Resource dialog that opens, select Menu from the list of available resources, as in Figure 6.1. Click the New button.

FIGURE 6.1. The Insert Resource dialog.

6. The Menu Designer opens in the editing area of Developer Studio. The first menu spot is highlighted, as shown in Figure 6.2.

FIGURE 6.2. An empty menu.

At this point, you have created the menu resource and you are ready to customize it by adding menu items. To add a menu item, follow these steps:

1. Right-click the mouse on the highlighted area and select Properties from the pop-up menu.

2. Enter the menu item's Caption. For this example, enter &File and close the Properties dialog.


NOTE: You are in the menu Properties dialog to specify the text that the user will see on the menu bar while the application is running. Because the Pop-up check box is checked (by default on any menu items on the top-level menu bar), this menu element doesn't trigger any application functionality and thus doesn't need to have an object ID assigned to it.
3. The first drop-down menu location is highlighted. To add this menu item, right-click the mouse again on the highlighted area and select Properties from the pop-up menu.

4. Enter an ID and caption for the menu item. For this example, enter IDM_FILE_HELLO for the ID and &Hello for the Caption. Close the dialog.


NOTE: This time in the menu Properties dialog, you not only specify the text that the user will see when the menu is opened from the menu bar, but you also specify the object ID that will be used in the event message handler to determine what function receives each of the menu events.

At this point you have created a menu with a single menu item. You can continue to add menu items by repeating steps 3 and 4 of the preceding list for each of the highlighted areas. You can also add separators onto the menu. A separator is a dividing line that runs across the menu to separate two functional areas of menu selections. To add a separator, perform the following steps:

FIGURE 6.3. Specifying a menu separator.

1. Select the highlighted area where you want the separator to be placed. In the example you created, the second drop-down menu location should be highlighted. Open the properties dialog as you did in step 3 in the preceding list. To add a separator, simply select the Separator option, as shown in Figure 6.3, and close the dialog.

To complete your sample program, follow the same steps I just described to add an Exit item to your File menu and a second menu called Help with one menu item called About. The following steps, which resemble the preceding list of steps, walk you through adding these additional items:

1. Open the properties dialog for the third drop-down location and specify the ID as IDM_FILE_EXIT and the caption as E&xit. Close the dialog.

2. Select the second top-level menu location and open the properties dialog. Specify the caption as &Help and close the dialog.

3. Open the properties dialog for the first drop-down location on the second top-level menu. Specify the ID as ID_HELP_ABOUT and the caption as &About. Close the dialog.

At this point, your menu is created; however, it is not attached to your application.

Attaching the Menu to Your Dialog Window

You now have a menu that you can use in your application. If you compile and run your application at this point, however, the menu doesn't appear. You still need to attach the menu to your dialog window. You can attach a menu by following these steps:

1. Open the dialog painter by double-clicking the primary application dialog in the Dialog folder in the Workspace pane. For this example, double-click on IDD_MENUS_DIALOG.

2. Select the entire dialog window, making sure that no controls are selected, and open the dialog's properties dialog. (What you are doing is opening the properties for the dialog window itself, not for any of the controls that might be on the window.)

3. Select the menu you have designed from the Menu drop-down list box, as shown in Figure 6.4.

FIGURE 6.4. Attaching the menu to the dialog window.

If you compile and run your application, you find that the menu is attached to the application dialog, as shown in Figure 6.5. You can select menu entries as you do with any other Windows application--with one small difference. At this point, when you select one of the menu entries, nothing happens. You still need to attach functionality to your menu.

FIGURE 6.5. The menu is now part of the application dialog.

Attaching Functionality to Menu Entries

Now that you have a menu as part of your application, it sure would be nice if it actually did something. Well, before your menu can do anything, you have to tell it what to do, just like everything else in your Visual C++ applications. To attach some functionality to your menu, follow these steps:

FIGURE 6.6. The menu is now part of the application.

1. Open the Menu Designer to your menu.

2. Open the Class Wizard from the View menu.

3. The Adding a Class dialog is displayed for you, just as it was yesterday when you added a second dialog. Leave the dialog selection on Select an Existing Class and click OK (see Figure 6.6).

Yesterday, when you were adding a second dialog window to your application, you needed to create a new C++ class for that window. For today's menu, you want to attach it to the existing C++ class for the dialog window to which the menu is attached.

4. Choose the C++ class of the primary dialog window from the list of available classes in the Select Class dialog. For this example, select CMenusDlg, as shown in Figure 6.7. This tells Visual C++ that all the functionality that you will call from the various menu entries is part of the same dialog class of the window that it's attached to.

FIGURE 6.7. The Select Class dialog.

For the menu elements that you want to use to trigger new functions in your application, you can add event-handler functions through the Class Wizard, just as you can with controls that you place on the dialog window.

For this example, add a function for the IDM_FILE_HELLO object (the Hello menu) on the COMMAND event message. Name the function OnHello and add the code in Listing 6.1 to the function.

LISTING 6.1. THE ONHELLO FUNCTION.

 1: void CMenusDlg::OnHello() 
 2: {
 3:     // TODO: Add your command handler code here
 4: 
 5:     ///////////////////////
 6:     // MY CODE STARTS HERE
 7:     ///////////////////////
 8: 
 9:     // Display a message for the user
10:     MessageBox("Hello there", "Hello");
11: 
12:     ///////////////////////
13:     // MY CODE ENDS HERE
14:     ///////////////////////
15: }


NOTE: The COMMAND event message is the message that is passed to the application window when a menu entry is selected. Placing a function on this event message has the same effect as placing a function on the menu entry selection.

You can call existing event handlers from menu elements by adding the existing function to the menu COMMAND event. You can do this by adding a function to the menu object ID and then specifying the existing function name instead of accepting the suggested function name.

To reuse the OnExit function for the Exit menu element, reopen the Menu Designer and then reopen the Class Wizard. When the Class Wizard is displayed, add a function for the IDM_FILE_EXIT object on the COMMAND event message. Do not accept the default function name presented to you by the Class Wizard. Enter the function name OnExit. This automatically attaches the existing OnExit function that you created with your Exit button earlier.

To round out your example's functionality, add a function to the ID_HELP_ABOUT object on the COMMAND event message. Edit the function as in Listing 6.2.

LISTING 6.2. THE ONHELPABOUT FUNCTION.

 1: void CMenusDlg::OnHelpAbout() 
 2: {
 3:     // TODO: Add your command handler code here
 4: 
 5:     ///////////////////////
 6:     // MY CODE STARTS HERE
 7:     ///////////////////////
 8: 
 9:     // Declare an instance of the About window
10:     CAboutDlg dlgAbout;
11: 
12:     // Show the About window
13:     dlgAbout.DoModal();
14: 
15:     ///////////////////////
16:     // MY CODE ENDS HERE
17:     ///////////////////////
18: }

You attached the File | Exit menu entry to an existing function that closes the application. On the File | Hello, you added a new function that called the MessageBox function to display a simple message to the user. With Help | About, you added another function that declared an instance of the About dialog window and called its DoModal method.

If you compile and run your application, you find that all the menu entries are working. If you select Help | About, as shown in Figure 6.8, you see the application About dialog (see Figure 6.9). If you select File | Hello, you see a Hello there message box, as shown in Figure 6.10. And if you select File | Exit, your application closes.

FIGURE 6.8. The Help | About menu entry.

FIGURE 6.9. The About dialog.

FIGURE 6.10. The Hello there message box.

Creating Pop-Up Menus

Most Windows applications have what are called either pop-up or context menus, which are triggered by the user right-clicking an object. These are called pop-up menus because they pop up in the middle of the application area, not attached to a menu bar, the window frame, or anything else on the computer screen (not counting the mouse pointer). These menus are often referred to as context menus because the contents of a menu depend on the context in which it is opened; the elements available on the menu depend on what objects are currently selected in the application or what the mouse pointer is positioned over.

To provide a pop-up menu in your application, you have two approaches available. You can either design a menu specifically for use as a pop-up menu, or you can use one of the pull-down menus from the primary menu that you have already designed. If you design a menu specifically for use as a pop-up menu, you will need to skip the top-level, menu bar element by placing a space or some other text in the caption, knowing that it will not be seen. You will see how this works when you build a custom menu specifically for use as a pop-up menu on Day 11, "Creating Multiple Document Interface Applications," in the section "Adding a Context Menu."

Every drop-down portion of a menu can also be used as a pop-up menu. To use it in this way, you must get a handle to the submenu (the drop-down menu) and then call the TrackPopupMenu function on the submenu. The rest of the pop-up menu functionality is already covered in the other menu building and coding that you have already done. To add a pop-up menu to your application, follow these steps:

1. Using the Class Wizard, add a function for the WM_CONTEXTMENU event message in your dialog window.


NOTE: There are two dialog event messages that you can use to trigger your context menu. The event that you'd expect to use is the WM_RBUTTONDOWN event, which is triggered by the user right-clicking. The other event that can (and should) be used is the WM_CONTEXTMENU event, which is intended for use specifically to trigger a context menu. This event is triggered by a couple user actions: One of these is the release of the right mouse button, and another is the pressing of the context menu button on one of the newer Windows-enabled keyboards.
2. Edit the function, adding the code in Listing 6.3.

LISTING 6.3. THE ONCONTEXTMENU FUNCTION.

 1: void CMenusDlg:: OnContextMenu(CWnd* pWnd, CPoint point) 
 2: {
 3:     // TODO: Add your message handler code here
 4:     
 5:     ///////////////////////
 6:     // MY CODE STARTS HERE
 7:     ///////////////////////
 8: 
 9:     // Declare local variables
10:     CMenu *m_lMenu;     // A pointer to the menu
11:     CPoint m_pPoint;    // A copy of the mouse position
12: 
13:     // Copy the mouse position to a local variable
14:     m_pPoint = point;
15:     // Convert the position to a screen position
16:     ClientToScreen(&m_pPoint);
17:     // Get a pointer to the window menu
18:     m_lMenu - GetMenu();
19:     // Get a pointer to the first submenu
20:     m_lMenu = m_lMenu->GetSubMenu(0);
21:     // Show the Popup Menu
22:     m_lMenu->TrackPopupMenu(TPM_CENTERALIGN + TPM_LEFTBUTTON,
23:         m_pPoint.x, m_pPoint.y, this, NULL);
24: 
25:     ///////////////////////
26:     // MY CODE ENDS HERE
27:     ///////////////////////
28: }

In Listing 6.3, the first thing that you did was make a copy of the mouse position. This mouse position is a relative position within the window area. It must be converted to an absolute position on the entire screen area for displaying the pop-up menu. If you don't convert the position coordinates, you can't predict where your pop-up menu will appear.

After you convert the position to an absolute position, you get a pointer to the window menu. This pointer should always be a local pointer within the function where you are going to use it because the location of the menu might change as the application runs. From the menu pointer, you next get a pointer to the first drop-down menu (submenu numbering begins with 0, like just about everything else in C/C++). After you have a pointer to the submenu, you can treat it as a regular CMenu class instance.

The final piece in this puzzle is the call to the CMenu member function TrackPopupMenu. This function takes five arguments and uses them to determine where and how to show the pop-up menu. The first argument is a combination of two flags. The first flag, TPM_CENTERALIGN, centers the pop-up menu on the mouse point. You can also use TPM_LEFTALIGN or TPM_RIGHTALIGN instead. These flags line up the left or right edge of the pop-up menu with the mouse position. The second part of this flag combination is TPM_LEFTBUTTON, which makes the pop-up menu trigger from the left mouse button. You can also use TPM_RIGHTBUTTON to make the menu trigger from the right mouse button.

The second and third arguments to the TrackPopupMenu function specify the screen position for the pop-up menu. This is the absolute position on the screen, not a relative position within the window area. The fourth argument is a pointer to the window that receives the menu command messages. The final argument is a rectangle that the user can click without closing the pop-up menu. By passing NULL, you specify that if the user clicks outside the pop-up menu, the menu closes. This code enables you to include a pop-up menu in your application, as shown in Figure 6.11.

FIGURE 6.11. The pop-up menu in action.

Creating a Menu with Accelerators

One of the original keyboard shortcuts for selecting menu entries were accelerator keys. As mentioned earlier in the chapter, accelerator keys are specific key combinations, usually the Ctrl key combined with another key, or function keys, that are unique within the entire application. Each of these key combinations triggers one menu event function.

The way that accelerator keys work is similar to the way menus work. They are also an application resource that is defined in a table in the resource tab of the workspace pane. Each table entry has an object ID and a key code combination. After you define the accelerators, you can attach functionality to the object IDs. You can also assign accelerator entries the same object ID as the corresponding menu entry so that you have to define only a single entry in the application message map.

After you define all your accelerator keys, you can add the key combination to the menu entry so that the user will know about the accelerator key combination. Add \t to the end of the menu entry caption, followed by the key combination. The \t is replaced in the menu display by a tab, which separates the menu caption from the accelerator key combination.

Unfortunately, accelerator keys don't work in dialog-style windows, so you cannot add them to today's application. You will learn how to attach accelerator keys to menus in a few days when you learn about single and multi-document interface style applications.

Summary

Today you learned about menus in Visual C++ applications. You learned how to use the tools in Visual C++ to create a menu for use in your application and then how to attach the menu to a window in your application. After you had the menu attached to your window, you learned how to attach functionality to the various menu entries. Later in the day, you learned how you can use a portion of your menu as a pop-up, or context, menu. Finally, you learned how accelerator keys are added to most applications.

Q&A

Q Do I have to name my menu items the same names everyone else uses? For example, a lot of applications use File and Help. Can I name my menus something else?

A You can name your top-level menus anything you want. However, there are ac-cepted menu name conventions that place all file-oriented functionality under a menu labeled File and all help-related functionality under a menu labeled Help. If you have a menu with entries such as Broccoli, Corn, and Carrots, you will probably want to call the menu Vegetables, although an equally valid label would be Food or Plants. In general, if you want to make your application easy for your users to learn, you will want to use menu labels that make sense for the entries o n the pull-down portion of the menu.

Q Why can't I specify a single character as an accelerator key?

A The single character would trigger the WM_KEY messages, not the menu messages. When the designers of Windows were deciding how accelerator keys would work, they decided that single-character keys would most likely be input to the active application. If they had allowed single-character accelerators, Windows wouldn't be able to determine whether the character was input or a shortcut. By requiring a key combination (with the exception of function keys), the designers ensured that Windows won't have to make this determination.

Workshop

The Workshop provides quiz questions to help you solidify your understanding of the material covered and exercises to provide you with experience in using what you've learned. The answers to the quiz questions are provided in Appendix B, "Answers."

Quiz

1. What event message does a menu selection send to the window message queue?

2. How do you attach a menu to a dialog window?

3. Which existing class do you specify for handling event messages for the menu?

4. What event message should a pop-up menu be triggered by?

Exercises

1. Add a button to the main window and have it call the same function as the Hello menu entry.

2. Add a pop-up menu to your application that uses the Help drop-down menu as the pop-up menu.


Previous chapterNext chapterContents

© Copyright, Macmillan Computer Publishing. All rights reserved.