e command in Figure 4-1 disables the menu item so that it can''''t be selected. A disabled item is "grayed out" as a visual reminder that it is disabled. Grayed menu text is displayed in the system color COLOR_GRAYTEXT, which defaults to gray, with a thin border added to provide a three-dimensional look. Another optional keyword is CHECKED, which places a check mark beside a menu item. Although common in Windows applications written in C using the SDK, menu item state specifiers are rarely used in MFC applications because the framework provides a powerful mechanism for updating menu items programmatically. You''''ll learn more about this mechanism shortly.
Loading and Displaying a Menu
At run time, a menu resource needs to be loaded and attached to a window. When the window is displayed, the menu will also be displayed.
One way to attach a menu to a window is to pass the menu''''s resource ID to CFrameWnd::Create. The following statement creates a frame window and attaches the menu whose resource ID is IDR_MAINFRAME:
Create (NULL, _T ("My Application"), WS_OVERLAPPEDWINDOW,
rectDefault, NULL, MAKEINTRESOURCE (IDR_MAINFRAME));
The sixth argument to Create identifies the menu resource. The MAKEINTRESOURCE macro converts an integer resource ID to an LPTSTR data type ID compatible with functions that expect string-based resource IDs. When the window appears on the screen, the menu will be visible just below the title bar.
A second method involves the CFrameWnd::LoadFrame function. Given a resource ID, LoadFrame creates a frame window and attaches a menu, much like Create. The statement
LoadFrame (IDR_MAINFRAME, WS_OVERLAPPEDWINDOW, NULL, NULL);
creates a window and attaches the menu IDR_MAINFRAME. Some MFC programs—particularly wizard-generated applications—use LoadFrame instead of Create because LoadFrame will load icons and other resources, too. MAKEINTRESOURCE isn''''t required in this example because it''''s built into LoadFrame.
Yet another method for loading a top-level menu and attaching it to a window is to construct a CMenu object, call CMenu::LoadMenu to load the menu resource, and call CWnd::SetMenu, like this:
CMenu menu;
menu.LoadMenu (IDR_MAINFRAME);
SetMenu (&menu);
menu.Detach ();
In this example, CMenu::Detach is called to detach the menu from the CMenu object so that the menu won''''t be destroyed prematurely when menu goes out of scope. The CMenu class helps guard against resource leaks by calling CMenu::DestroyMenu from its destructor. As a rule, a menu loaded with LoadMenu should be destroyed with DestroyMenu before the application that loaded the menu terminates. However, a menu attached to a window is automatically destroyed when the window is destroyed, so detaching a menu from a CMenu object after attaching it to a window won''''t cause a resource leak unless the menu is later detached from the window without a subsequent call to DestroyMenu.
The SetMenu technique offers no advantage over simply passing the menu ID to Create or LoadFrame when a program contains just one menu, but it''''s very useful in programs that contain two or more menus. Suppose you want to write an application that allows the user to choose short or long menus. Here''''s one way to go about it. First, create two menu resources—one for the short menus, another for the long. At startup, load the menu resources into CMenu data members named m_menuLong and m_menuShort. Then choose the menu type based on the value of a BOOL data member named m_bShortMenu, which is TRUE if short menus are selected and FALSE if they''''re not. Here''''s what the window''''s constructor might look like:
Create (NULL, _T ("My Application"));
m_menuLong.LoadMenu (IDR_LONGMENU);
m_menuShort.LoadMenu (IDR_SHORTMENU);
SetMenu (m_bShortMenu ? &m_menuShort : &m_menuLong);
In response to a command from the user, the following code would switch from long menus to short menus:
m_bShortMenu = TRUE;
SetMenu (&m_menuShort);
DrawMenuBar ();
And these statements would switch back to long menus:
m_bShortMenu = FALSE;
SetMenu (&m_menuLong);
DrawMenuBar ();
CWnd::DrawMenuBar redraws the menu bar to reflect the change. You should always follow calls to SetMenu with calls to DrawMenuBar unless the window isn''''t visible on the screen.
What about code to delete the menus, since only one will be attached to a window when the application ends? If m_menuLong and m_menuShort are data members of the frame window class, their destructors will be called when the frame window is destroyed and the menus associated with them will also be deleted. Therefore, explicit calls to DestroyMenu aren''''t required.
Responding to Menu Commands
When the user pulls down a menu, the window to which the menu is attached receives a series of messages. Among the first to arrive is a WM_INITMENU message notifying the window that a top-level menu item was selected. Before a submenu is displayed, the window receives a WM_INITMENUPOPUP message. Windows programs sometimes take this opportunity to update the submenu''''s menu items—for example, putting a check mark next to the Toolbar item in the View menu if the application''''s toolbar is displayed or unchecking the menu item if the toolbar is currently hidden. As the highlight travels up and down the menu, the window receives WM_MENUSELECT messages reporting the latest position in the menu. In SDK-style programs, WM_MENUSELECT messages are sometimes used to display context-sensitive menu help in a status bar.
The most important message of all is the WM_COMMAND message sent when the user selects an item from the menu. The low word of the message''''s wParam parameter holds the item''''s command ID. SDK programmers often use switch-case logic to vector execution to the appropriate handling routine, but MFC provides a better way. An ON_COMMAND statement in the message map links WM_COMMAND messages referencing a particular menu item to the class member function, or command handler, of your choice. The following message-map entry tells MFC to call OnFileSave when the ID_FILE_SAVE menu item is selected:
ON_COMMAND (ID_FILE_SAVE, OnFileSave)
Other items in the File menu might be mapped like this:
ON_COMMAND (ID_FILE_NEW, OnFileNew)
ON_COMMAND (ID_FILE_OPEN, OnFileOpen)
ON_COMMAND (ID_FILE_SAVE, OnFileSave)
ON_COMMAND (ID_FILE_SAVE_AS, OnFileSaveAs)
ON_COMMAND (ID_FILE_EXIT, OnFileExit)
Now OnFileNew will be activated when File-New is selected, OnFileOpen will be called when File-Open is selected, and so on.
Command handlers take no arguments and return no values. The OnFileExit function, for example, is typically implemented like this
void CMainWindow::OnFileExit ()
{
PostMessage (WM_CLOSE, 0, 0);
}
This command handler terminates the application by posting a WM_CLOSE message to the application''''s main window. This message ultimately ends the application by causing a WM_QUIT message to appear in the application''''s message queue.
You can name command handlers whatever you like. There are no naming criteria as there are for WM_ message handlers. Handlers for WM_PAINT and WM_CREATE must be named OnPaint and OnCreate unless you care to rewrite MFC''''s ON_WM_PAINT and ON_WM_CREATE macros. But you could just as easily have written the message-map entries for our File menu like this:
ON_COMMAND (ID_FILE_NEW, CreateMeAFile)
ON_COMMAND (ID_FILE_OPEN, OpenMeAFile)
ON_COMMAND (ID_FILE_SAVE, SaveThisFile)
ON_COMMAND (ID_FILE_SAVE_AS, SaveThisFileUnderAnotherName)
ON_COMMAND (ID_FILE_EXIT, KillThisAppAndDoItNow)
Command Ranges
Sometimes it''''s more efficient to process a group of menu item IDs with a single command handler than to provide a separate member function for each ID. Consider a drawing application that contains a Color menu from which the user can choose red, green, or blue. Selecting a color from the menu sets a member variable named m_nCurrentColor to 0, 1, or 2 and subsequently changes the color of what the user draws on the screen. The message-map entries and command handlers for these menu items might be implemented as follows:
// In CMainWindow''''s message map
ON_COMMAND (ID_COLOR_RED, OnColorRed)
ON_COMMAND (ID_COLOR_GREEN, OnColorGreen)
ON_COMMAND (ID_COLOR_BLUE, OnColorBlue)
void CMainWindow::OnColorRed ()
{
m_nCurrentColor = 0;
}
void CMainWindow::OnColorGreen ()
{
m_nCurrentColor = 1;
}
void CMainWindow::OnColorBlue ()
{
m_nCurrentColor = 2;
}
This isn''''t a terribly efficient way to process messages from the Color menu because each message handler does essentially the same thing. And the inefficiency would be compounded if the menu contained 10 or 20 different colors rather than just 3.
One way to reduce the redundancy in the command handlers for the Color menu is to map all three items to the same CMainWindow member function and retrieve the menu item ID with CWnd::GetCurrentMessage, as shown below.
// In CMainWindow''''s message map
ON_COMMAND (ID_COLOR_RED, OnColor)
ON_COMMAND (ID_COLOR_GREEN, OnColor)
ON_COMMAND (ID_COLOR_BLUE, OnColor)
上一页 [1] [2] [3] [4] 下一页 [常用软件][设计]Flashation Menu Builder 菜单软件教学 [Delphi程序]Create a menu item into the Delphi menu [VB.NET程序]WAP Basics [VB.NET程序]Event-Handling Basics [VB.NET程序]Internet Basics [Web开发]利用JavaScript和CSS制作浮动menu [MySql]linux下的c 编程------控制台下的menu
|