Q100770: HOWTO: Use Accelerator Keys with Modal Dialog Box Main Window
Article: Q100770
Product(s): Microsoft C Compiler
Version(s): 2.0,2.1,4.0,5.0,6.0
Operating System(s):
Keyword(s): kbui kbGrpDSMFCATL kbVC100 kbVC150 kbVC151 kbVC152 kbVC200 kbVC210 kbVC400 kbVC500 kbVC
Last Modified: 26-JUL-2002
-------------------------------------------------------------------------------
The information in this article applies to:
- The Microsoft Foundation Classes (MFC), used with:
- Microsoft Visual C++
- Microsoft Visual C++, 32-bit Editions, versions 2.0, 2.1, 4.0, 5.0, 6.0
- Microsoft Visual C#.NET (2002)
-------------------------------------------------------------------------------
SUMMARY
=======
Many applications use a modal dialog box as the main application window.
Applications that use this technique may also include a main menu on the dialog
box. Typically, one or more of the menu items has a keyboard accelerator
associated with it. This article describes the steps that are required to add a
menu and keyboard accelerators to an MFC Application Wizard dialog box-based
application.
MORE INFORMATION
================
A typical application that is developed for the Microsoft Windows operating
system by using Visual C++ and the Microsoft Windows Software Development Kit
(SDK) and that uses keyboard accelerators calls the TranslateAccelerator()
function in its main message loop. However, when you use a modal dialog box as
the main window, the application does not have a main message loop; instead, the
application uses the dialog box manager message loop (built into Windows) to
translate and dispatch messages. Of course, because this message loop is not
designed to process accelerators, it does not call the TranslateAccelerator()
function.
To process accelerator keys in a modal dialog box in MFC, you must override the
CWinApp::ProcessMessageFilter() function. The framework calls
ProcessMessageFilter() before it processes a message.
To modify an MFC Application Wizard dialog box-based application type in Visual
C++ .NET to correctly process accelerator keys, follow these steps:
1. In Visual Studio .NET, create a new MFC application. In the left pane of the
MFC Application Wizard, click Application Type, and then make sure that
Application type is set to Dialog based.
2. In Resource view, double-click the dialog resource to open the dialog
resource editor. The resource ID of the dialog resource is similar to
IDD_<MYPROJECT>_DIALOG (where <MYPROJECT> is the name that you
gave your application project when you created it).
3. With the dialog resource open in the dialog resource editor, locate the
Properties window. Edit the dialog box Border property and specify the Thin
border style. This step is required for a dialog box that contains a menu.
4. Create a new menu resource that contains a top-level entry named &File
and a menu item named &Exit\tCTRL+E (CTRL+X is usually associated with
cutting text, so CTRL+E is used instead).
5. In the menu editor, click the newly created Exit menu item. In the Properties
window, make sure that the ID property for the Exit menu item is set to
ID_FILE_EXIT.
6. Associate the new menu with the dialog box by entering the menu ID in the
dialog resource Menu property. Open the dialog editor for the dialog resource
and find the Menu property in the Properties window. Set it to the resource
ID that you created for the menu in step 4. To do this, click the drop-down
list in the Menu property row, and then click to select the resource ID for
the menu in the list.
7. In the menu editor, right-click &Exit\tCTRL+E, and then click Add Event
Handler.
8. In the Event Handler Wizard, select the COMMAND message type. In the Class
list, select the CDialog derived main class for the handler to be generated
in. Make sure that the function handler name is appropriate, and then click
Add and Edit to create the menu item event handler.
9. Insert the following line in the function Exit menu item event handler method
that is generated in step 8:
PostMessage(WM_COMMAND, IDOK, 0L);
This produces the same effect as clicking OK when the user clicks Exit on the
File menu. Clicking OK closes your dialog box application.
10. Create a new accelerator resource and associate the CTRL+E key combination
with ID_FILE_EXIT. Save your changes.
11. Edit the Stdafx.h file to declare the following global variables after the
#include statements:
extern HWND ghDlg; // Handle to main dialog box.
extern HACCEL ghAccelTable; // Handle to accelerator table.
12. In the .cpp file that contains the CWinApp derived class implementation
(usually the .cpp file with the same base name as your project name), add
the following global variable initializations:
HWND ghDlg = 0; // Handle to main dialog box.
HACCEL ghAccelTable = 0; // Handle to accelerator table.
13. In the main CDialog derived class (not the dialog class that implements the
default About dialog box), find the OnInitDialog() method. If necessary, you
can add an override for the OnInitDialog() method. To do this, click to
select the CDialog derived class in the Class View window, and then click
Overrides in the Properties window. Find the OnInitDialog row and click the
right column. If OnInitDialog() is not overridden for this class, you have
the option to create an override.
14. Edit the function that you added earlier to include the following line of
code:
ghDlg = m_hWnd;
15. In the .cpp file that contains the CWinApp derived implementation, find the
InitInstance() class method. Add the following line immediately after the
call to the base class CWinApp::InitInstance():
ghAccelTable = LoadAccelerators(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDR_ACCELERATOR1));
NOTE: The resource ID that is used here (IDR_ACCELERATOR1) is the ID of the
accelerator table resource that is added in step 10.
16. Add an override to the CWinApp derived class for the ProcessMessageFilter()
class method. To do this, in the Class View window, select the CWinApp
derived class in your project. Then, in the Properties window, click
Overrides. Find the ProcessMessageFilter row in the Properties window and
select the right-most column of that row. Click the drop-down arrow, and
then click the option to add an override for the ProcessMessageFilter
method.
17. Edit the ProcessMessageFilter() method override so that it has the following
implementation:
BOOL CMyProjectApp::ProcessMessageFilter(int code, LPMSG lpMsg)
{
if (code < 0)
CWinApp::ProcessMessageFilter(code, lpMsg);
if (ghDlg && ghAccelTable)
{
if (::TranslateAccelerator(ghDlg, ghAccelTable, lpMsg))
return(TRUE);
}
return CWinApp::ProcessMessageFilter(code, lpMsg);
}
18. Compile and run the application. Note that it has a menu. When you click
Exit on the File menu or press CTRL+E, the application closes, as expected.
Additional query words:
======================================================================
Keywords : kbui kbGrpDSMFCATL kbVC100 kbVC150 kbVC151 kbVC152 kbVC200 kbVC210 kbVC400 kbVC500 kbVC600 kbKeyAccel kbMenu kbMFC kbAcceleratorKey
Technology : kbAudDeveloper kbMFC
Version : :2.0,2.1,4.0,5.0,6.0
Issue type : kbhowto
=============================================================================
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 1986-2002.