Command Processing

As you saw in Chapter 2, the application framework provides a sophisticated routing system for command messages. These messages originate from menu selections, keyboard accelerators, and toolbar and dialog button clicks. Command messages can also be sent by calls to the CWnd::SendMessage or PostMessage function. Each message is identified by a #define constant that is often assigned by a resource editor. The application framework has its own set of internal command message IDs, such as ID_FILE_PRINT and ID_FILE_OPEN. Your project's resource.h file contains IDs that are unique to your application.

Most command messages originate in the application's frame window, and without the application framework in the picture, that's where you would put the message handlers. With command routing, however, you can handle a message almost anywhere. When the application framework sees a frame window command message, it starts looking for message handlers in one of the sequences listed here.

SDI ApplicationMDI Application
ViewView
DocumentDocument
SDI main frame windowMDI child frame window
ApplicationMDI main frame window
Application

Most applications have a particular command handler in only one class, but suppose your one-view application has an identical handler in both the view class and the document class. Because the view is higher in the command route, only the view's command handler function will be called.

What is needed to install a command handler function? The installation requirements are similar to those of the window message handlers you've already seen. You need the function itself, a corresponding message map entry, and the function prototype. Suppose you have a menu item named Zoom (with IDM_ZOOM as the associated ID) that you want your view class to handle. First you add the following code to your view implementation file:

BEGIN_MESSAGE_MAP(CMyView, CView)     ON_COMMAND(IDM_ZOOM, OnZoom) END_MESSAGE_MAP() void CMyView::OnZoom() {     // command message processing code } 

Now add the following function prototype to the CMyView class header file (before the DECLARE_MESSAGE_MAP macro):

afx_msg void OnZoom();

Of course, ClassWizard automates the process of inserting command message handlers the same way it facilitates the insertion of window message handlers. You'll learn how this works in the next example, EX13A.

Command Message Handling in Derived Classes

The command routing system is one dimension of command message handling. The class hierarchy is a second dimension. If you look at the source code for the MFC library classes, you'll see lots of ON_COMMAND message map entries. When you derive a class from one of these base classes—for example, CView—the derived class inherits all the CView message map functions, including the command message functions. To override one of the base class message map functions, you must add both a function and a message map entry to your derived class.

Update Command User Interface Handlers

You often need to change the appearance of a menu item to match the internal state of your application. If your application's Edit menu includes a Clear All item, for example, you might want to disable that item if there's nothing to clear. You've undoubtedly seen such grayed menu items in Windows-based applications, and you've probably also seen check marks next to menu items.

With Win32 programming, it's difficult to keep menu items synchronized with the application's state. Every piece of code that changes the internal state must contain statements to update the menu. The MFC library takes a different approach by calling a special update command user interface (UI) handler function whenever a pop-up menu is first displayed. The handler function's argument is a CCmdUI object, which contains a pointer to the corresponding menu item. The handler function can then use this pointer to modify the menu item's appearance. Update command UI handlers apply only to items on pop-up menus, not to top-level menu items that are permanently displayed. You can't use an update command UI handler to disable a File menu item, for example.

The update command UI coding requirements are similar to those for commands. You need the function itself, a special message map entry, and of course the prototype. The associated ID—in this case, IDM_ZOOM—is the same constant used for the command. Here is an example of the necessary additions to the view class code file:

BEGIN_MESSAGE_MAP(CMyView, CView)     ON_UPDATE_COMMAND_UI(IDM_ZOOM, OnUpdateZoom) END_MESSAGE_MAP() void CMyView::OnUpdateZoom(CCmdUI* pCmdUI) {     pCmdUI->SetCheck(m_bZoomed); // m_bZoomed is a class data member } 

Here is the function prototype that you must add to the class header (before the DECLARE_MESSAGE_MAP macro):

afx_msg void OnUpdateZoom(CCmdUI* pCmdUI);

Needless to say, ClassWizard automates the process of inserting update command UI handlers.

Commands That Originate in Dialogs

Suppose you have a pop-up dialog with buttons, and you want a particular button to send a command message. Command IDs must be in the range 0x8000 to 0xDFFF, the same ID range that the resource editor uses for your menu items. If you assign an ID in this range to a dialog button, the button will generate a routable command. The application framework first routes this command to the main frame window because the frame window owns all pop-up dialogs. The command routing then proceeds normally; if your view has a handler for the button's command, that's where it will be handled. To ensure that the ID is in the range 0x8000 to 0xDFFF, you must use Visual C++'s symbol editor to enter the ID prior to assigning the ID to a button.



Programming Microsoft Visual C++
Programming Microsoft Visual C++
ISBN: 1572318570
EAN: 2147483647
Year: 1997
Pages: 332

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net