Monday, April 1, 2013

visual c++(mfc) program to choose a menu item using keyboard accelerator key

             /*TO CHOOSE A MENU ITEM USING KEYBOARD ACCELERATOR KEY*/


#include<afxwin.h>
#include"resource.h"
class myframe:public CFrameWnd
{
public:
          myframe()
          {
          LoadAccelTable(MAKEINTRESOURCE(IDR_ACCELERATOR1));
            Create(0,"my mfc",WS_OVERLAPPEDWINDOW,rectDefault,0,MAKEINTRESOURCE(IDR_MENU1));
          }
          void line()
          {
              RedrawWindow();
              CClientDC dc(this);
              dc.LineTo(100,100);
          }
       
             
          void rectangle()
          {
              RedrawWindow();
              CClientDC dc(this);
              dc.Rectangle(100,100,200,200);
          }
       
          DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(myframe,CFrameWnd)
ON_COMMAND(1,line)
ON_COMMAND(2,rectangle)
END_MESSAGE_MAP()
class myapp:public CWinApp
{
public:
        virtual BOOL InitInstance()
        {
           m_pMainWnd=new myframe();
           m_pMainWnd->ShowWindow(1);
           m_pMainWnd->UpdateWindow();
           return TRUE;
        }
};
myapp app;


MFC Menus


Menu programming is the next step to be learnt in MFC after learning message maps. MFC provides two ways of programming menus. One is by using the resource option and the second is by using the dynamic menu option. This part of MFC Tutorial discusses about the Resource option.
    The following steps will explain how to add a menu to this MFC Tutorial application.

    Step 1:
        Create the project with out adding any files by selecting "Empty project" option.
    Step 2:
        After the project gets created, click on Project --> Add To Project --> New and select SourceFile (.cpp File) option. Give any name to the file and click OK.

    Step 3:
        Copy the previous MFC Tutorial 2 code. Do not forget to choose the MFC Library by clicking Menu --> Project --> Settings --> General --> Microsoft Foundation Classes as "Use MFC as Shared Library".
    Step 4:
        Choose Menu --> Insert --> Resource. Select Menu from the list of resources. Click "New" and create one popup item as "File" and one menu item under this "File" as "New". Press enter on this "New" menu item and open the properties. Enter IDM_FILE_NEW as the menu resource ID in the resource id box. Press the Enter key again.
    Step 5:
        A new resource file will be created. Save this resource file.
    Step 6:
        Click Project --> Add To Project --> Files and select the two new filesScript1.rc and resource.h.
    Step 7:
        Now add the highlighted code into the project at the appropriate places. This code shows you how to
  • load the menu resource into a CMenu class
  • set the menu to the window
  • writing handlers for the menu items.



Using ProcessMessageFilter to handle dialog-based accelerator keys

Let's say you have a menu in your dialog based app. And you have an accelerator key for some particular task. You'll soon be disappointed to find that the hotkey does not work. The problem is that the modal dialog app's message loop does not call TranslateAccelerator. I do not know why this is so. Presumable the Microsoft team decided that people shouldn't use dialog based apps to write complicated applications, with hotkeys and menus.
But as usual they have suggested a workaround too. Here's is how you go about implementing it. I'd like to state again, that even though this is a Microsoft recommended technique there will be a good majority of MFC gurus, like Joseph Newcomer for example, who would tell you that you shouldn't be doing this. But then sometimes you have to sacrifice elegance for getting things done quickly and with minimum effort.
  • Add a member variable to your CWinApp derived class.
  • HACCEL m_haccel;
  • Use the resource editor to create a new Accelerator, by default it will be named IDR_ACCELERATOR1. And add a new accelerator key that is a short cut for some menu item.
  • Put the following line in your InitInstance just before the line where the CDialog derived object is declared
  • m_haccel=LoadAccelerators(AfxGetInstanceHandle(), 
            MAKEINTRESOURCE(IDR_ACCELERATOR1));
  • Now override ProcessMessageFilter and modify the function so that it looks like :-
    BOOL CPreTransTestApp::ProcessMessageFilter(int code, LPMSG lpMsg) 
    {
        if(m_haccel)
        {
            if (::TranslateAccelerator(m_pMainWnd->m_hWnd, m_haccel, lpMsg)) 
                return(TRUE);
        }
     
        return CWinApp::ProcessMessageFilter(code, lpMsg);
    }
All we did was to call TranslateAccelerator and if it succeeds then we don't need to call the base class ProcessMessageFilter, as the message has been handled. So we return TRUE.

No comments:

Post a Comment