MFC - Messages & Events

An application is made of various objects. Most of the time, more than one application is running on the computer and the operating system is constantly asked to perform some assignments. Because there can be so many requests presented unpredictably, the operating system leaves it up to the objects to specify what they want, when they want it, and what behavior or result they expect.
The Microsoft Windows operating system cannot predict what kinds of requests one object would need to be taken care of and what type of assignment another object would need.
The Microsoft Windows operating system cannot predict what kinds of requests one object would need to be taken care of and what type of assignment another object would need.
To manage all these assignments and requests, the objects send messages.
To manage all these assignments and requests, the objects send messages.
Each object has the responsibility to decided what message to send and when.
Each object has the responsibility to decided what message to send and when.
In order to send a message, a control must create an event.
In order to send a message, a control must create an event.
To make a distinction between the two, a message's name usually starts with WM_ which stands for Window Message.
To make a distinction between the two, a message's name usually starts with WM_ which stands for Window Message.
The name of an event usually starts with On which indicates an action.
The name of an event usually starts with On which indicates an action.
The event is the action of sending the message.
The event is the action of sending the message.
Since Windows is a message-oriented operating system, a large portion of programming for the Windows environment involves message handling. Each time an event such as a keystroke or mouse click occurs, a message is sent to the application, which must then handle the event.
For the compiler to manage messages, they should be included in the class definition.
For the compiler to manage messages, they should be included in the class definition.
The DECLARE_MESSAGE_MAP macro should be provided at the end of the class definition as shown in the following code.
The DECLARE_MESSAGE_MAP macro should be provided at the end of the class definition as shown in the following code.
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      DECLARE_MESSAGE_MAP()
};
The actual messages should be listed just above the DECLARE_MESSAGE_MAP line.
The actual messages should be listed just above the DECLARE_MESSAGE_MAP line.
To implement the messages, you need to create a table of messages that your program is using.
To implement the messages, you need to create a table of messages that your program is using.
This table uses two delimiting macros;
This table uses two delimiting macros;
Its starts with a BEGIN_MESSAGE_MAP and ends with an END_MESSAGE_MAP macros.
Its starts with a BEGIN_MESSAGE_MAP and ends with an END_MESSAGE_MAP macros.
The BEGIN_MESSAGE_MAP macro takes two arguments, the name of your class and the MFC class you derived your class from as shown in the following code.
The BEGIN_MESSAGE_MAP macro takes two arguments, the name of your class and the MFC class you derived your class from as shown in the following code.
#include <afxwin.h>
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      DECLARE_MESSAGE_MAP()
};
CMainFrame::CMainFrame() {

   // Create the window's frame
   Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW,
                                      CRect(120, 100, 700, 480), NULL);
}
class CMessagesApp : public CWinApp {
   public:
      BOOL InitInstance();
};
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
END_MESSAGE_MAP()
BOOL CMessagesApp::InitInstance(){
   m_pMainWnd = new CMainFrame;
   m_pMainWnd->ShowWindow(SW_SHOW);
   m_pMainWnd->UpdateWindow();
   return TRUE;
}
CMessagesApp theApp;
Let us look into a simple example by creating a new Win32 project.
Step 1 − To create an MFC project, right-click on the project and select Properties.
Step 2 − In the left section, click Configuration Properties → General.
Step 3 − Select the ‘Use MFC in Shared DLL’ option in Project Defaults section and click OK.
Step 4 − We need to add a new source file.
Step 5 − Right-click on your Project and select Add → New Item.
Step 6 − In the Templates section, click C++ File (.cpp).
Step 7 − Click Add to Continue.
Step 8 − Now, add the following code in the *.cpp file.
#include <afxwin.h>
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      DECLARE_MESSAGE_MAP()
};

CMainFrame::CMainFrame() {
   // Create the window's frame
   Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW,
      CRect(120, 100, 700, 480), NULL);
}

class CMessagesApp : public CWinApp {
   public:
      BOOL InitInstance();
};

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
END_MESSAGE_MAP()
BOOL CMessagesApp::InitInstance() {
   m_pMainWnd = new CMainFrame;
   m_pMainWnd->ShowWindow(SW_SHOW);
   m_pMainWnd->UpdateWindow();
   return TRUE;
}
CMessagesApp theApp;
There are different types of Windows messages like creating a window, showing a window etc. Here are some of the commonly used windows messages.
Let us look into a simple example of window creation.
WM_CREATE − When an object, called a window, is created, the frame that creates the objects sends a message identified as ON_WM_CREATE.
Step 1 − To create ON_WM_CREATE, add afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); before the DECLARE_MESSAGE_MAP() as shown below.
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
      DECLARE_MESSAGE_MAP()
};
Step 2 − Add the ON_WM_CREATE() after the BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) and before END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_CREATE()
END_MESSAGE_MAP()
Step 3 − Here is the Implementation of OnCreate()
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
   // Call the base class to create the window
   if (CFrameWnd::OnCreate(lpCreateStruct) == 0) {

      // If the window was successfully created, let the user know
      MessageBox(L"The window has been created!!!");
      // Since the window was successfully created, return 0
      return 0;
   }
   // Otherwise, return -1
   return -1;
}
Step 4 − Now your *.cpp file will look like as shown in the following code.
#include <afxwin.h>
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
      DECLARE_MESSAGE_MAP()
};
CMainFrame::CMainFrame() {

   // Create the window's frame
   Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW,
      CRect(120, 100, 700, 480), NULL);
}
class CMessagesApp : public CWinApp {
   public:
      BOOL InitInstance();
};
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_CREATE()
END_MESSAGE_MAP()
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
   // Call the base class to create the window
   if (CFrameWnd::OnCreate(lpCreateStruct) == 0) {
      // If the window was successfully created, let the user know
      MessageBox(L"The window has been created!!!");
      // Since the window was successfully created, return 0
      return 0;
   }
   // Otherwise, return -1
   return -1;
}
BOOL CMessagesApp::InitInstance() { 
   m_pMainWnd = new CMainFrame;
   m_pMainWnd -> ShowWindow(SW_SHOW);
   m_pMainWnd -> UpdateWindow();
   return TRUE;
}
CMessagesApp theApp;
Step 5 − When the above code is compiled and executed, you will see the following output.
Step 6 − When you click OK, it will display the main window.
One of the main features of a graphical application is to present Windows controls and resources that allow the user to interact with the machine. Examples of controls that we will learn are buttons, list boxes, combo boxes, etc.
One type of resource we introduced in the previous lesson is the menu. Such controls and resources can initiate their own messages when the user clicks them. A message that emanates from a Windows control or a resource is called a command message.
Let us look into a simple example of Command messages.
To provide your application the ability to create a new document, the CWinApp class provides the OnFileNew() method.
afx_msg void OnFileNew();

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_COMMAND(ID_FILE_NEW, CMainFrame::OnFileNew)
END_MESSAGE_MAP()
Here is the method definition −
void CMainFrame::OnFileNew() {
   // Create New file
}
A keyboard is a hardware object attached to the computer. By default, it is used to enter recognizable symbols, letters, and other characters on a control. Each key on the keyboard displays a symbol, a letter, or a combination of those, to give an indication of what the key could be used for. The user typically presses a key, which sends a signal to a program.
Each key has a code that the operating system can recognize. This code is known as the virtual key code.
VK_LBUTTON
Left mouse button
VK_RBUTTON
Right mouse button
VK_CANCEL
Control-break processing
VK_MBUTTON
Middle mouse button (three-button mouse)
VK_BACK
BACKSPACE key
VK_RETURN
ENTER key
VK_TAB
TAB key
VK_CLEAR
CLEAR key
VK_SHIFT
SHIFT key
VK_CONTROL
CTRL key
VK_MENU
ALT key
VK_PAUSE
PAUSE key
VK_CAPITAL
CAPS LOCK key
VK_ESCAPE
ESC key
VK_SPACE
SPACEBAR
VK_PRIOR
PAGE UP key
VK_NEXT
PAGE DOWN key
VK_END
END key
VK_HOME
HOME key
VK_LEFT
LEFT ARROW key
VK_UP
UP ARROW key
VK_RIGHT
RIGHT ARROW key
VK_DOWN
DOWN ARROW key
VK_SELECT
SELECT key
VK_PRINT
PRINT key
VK_EXECUTE
EXECUTE key
VK_SNAPSHOT
PRINT SCREEN key
VK_INSERT
INS key
VK_DELETE
DEL key
VK_NUMPAD0
Numeric keypad 0 key
VK_NUMPAD1
Numeric keypad 1 key
VK_NUMPAD2
Numeric keypad 2 key
VK_NUMPAD3
Numeric keypad 3 key
VK_NUMPAD4
Numeric keypad 4 key
VK_NUMPAD5
Numeric keypad 5 key
VK_NUMPAD6
Numeric keypad 6 key
VK_NUMPAD7
Numeric keypad 7 key
VK_NUMPAD8
Numeric keypad 8 key
VK_NUMPAD9
Numeric keypad 9 key
VK_MULTIPLY
Multiply key
VK_ADD
Add key
VK_SEPARATOR
Separator key
VK_SUBTRACT
Subtract key
VK_DECIMAL
Decimal key
VK_DIVIDE
Divide key
VK_F1
F1 key
VK_F2
F2 key
VK_F3
F3 key
VK_F4
F4 key
VK_F5
F5 key
VK_F6
F6 key
VK_F7
F7 key
VK_F8
F8 key
VK_F9
F9 key
VK_F10
F10 key
VK_F11
F11 key
VK_F12
F12 key
VK_NUMLOCK
NUM LOCK key
VK_SCROLL
SCROLL LOCK key
VK_LSHIFT
Left SHIFT key
VK_RSHIFT
Right SHIFT key
VK_LCONTROL
Left CONTROL key
VK_RCONTROL
Right CONTROL key
Pressing a key causes a WM_KEYDOWN or WM_SYSKEYDOWN message to be placed in the thread message. This can be defined as follows −
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
Let us look into a simple example.
Step 1 − Here is the message.
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_CREATE()
   ON_WM_KEYDOWN()
END_MESSAGE_MAP()
Step 2 − Here is the implementation of OnKeyDown().
void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
   switch (nChar) {

      case VK_RETURN:
         MessageBox(L"You pressed Enter");
         break;
      case VK_F1:
         MessageBox(L"Help is not available at the moment");
         break;
      case VK_DELETE:
         MessageBox(L"Can't Delete This");
         break;
      default:
         MessageBox(L"Whatever");
   }
}
Step 3 − When the above code is compiled and executed, you will see the following output.
Step 4 − When you press Enter, it will display the following message.
The mouse is another object that is attached to the computer allowing the user to interact with the machine.
If the left mouse button was pressed, an ON_WM_LBUTTONDOWN message is sent. The syntax of this message is − 

afx_msg void OnLButtonDown(UINT nFlags, CPoint point)


If the left mouse button was pressed, an ON_WM_LBUTTONDOWN message is sent. The syntax of this message is − 
afx_msg void OnLButtonDown(UINT nFlags, CPoint point)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point)
If the right mouse button was pressed, an ON_WM_RBUTTONDOWN message is sent. Its syntax is −

afx_msg void OnRButtonDown(UINT nFlags, CPoint point)


If the right mouse button was pressed, an ON_WM_RBUTTONDOWN message is sent. Its syntax is −
afx_msg void OnRButtonDown(UINT nFlags, CPoint point)
afx_msg void OnRButtonDown(UINT nFlags, CPoint point)
Similarly If the left mouse is being released, the ON_WM_LBUTTONUP message is sent. Its syntax is −

afx_msg void OnLButtonUp(UINT nFlags, CPoint point)


Similarly If the left mouse is being released, the ON_WM_LBUTTONUP message is sent. Its syntax is −
afx_msg void OnLButtonUp(UINT nFlags, CPoint point)
afx_msg void OnLButtonUp(UINT nFlags, CPoint point)
If the right mouse is being released, the ON_WM_TBUTTONUP message is sent. Its syntax is −

afx_msg void OnRButtonUp(UINT nFlags, CPoint point)


If the right mouse is being released, the ON_WM_TBUTTONUP message is sent. Its syntax is −
afx_msg void OnRButtonUp(UINT nFlags, CPoint point)
afx_msg void OnRButtonUp(UINT nFlags, CPoint point)
Let us look into a simple example.
Step 1 − Add the following two functions in CMainFrame class definition as shown in the following code.
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
      afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
      afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
      DECLARE_MESSAGE_MAP()
};
Step 2 − Add the following two Message Maps.
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_KEYDOWN()
   ON_WM_LBUTTONDOWN()
   ON_WM_RBUTTONUP()
END_MESSAGE_MAP()
Step 3 − Here is the functions definition.
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) { 
   CString MsgCoord;
   MsgCoord.Format(L"Left Button at P(%d, %d)", point.x, point.y);
   MessageBox(MsgCoord);
}
void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) { 
   MessageBox(L"Right Mouse Button Up");
}
Step 4 − When you run this application, you will see the following output.
Step 5 − When you click OK, you will see the following message.
Step 6 − Right-click on this window. Now, when you release the right button of the mouse, it will display the following message.
 Print
 Add Notes
 Bookmark this page