1. Windows Messages and Message Handling
Software application user interacts with the windows applications through the main external devices like Keyboard and Mouse. In MFC, hardware events from these devices are seen as ‘Windows Messages’. An MFC application programs responding to these windows messages are called ‘Message Handling’.
For Example, Let us say, a user clicks Left Mouse button in the “Windows Client Area” of an MFC SDI Application, and after that, a message box pops up greeting “Hello there”. Here, the “Mouse Click” is sent to the application as Windows Message, and a “Handler Function” is showing the message box by responding to the received message.
In this example, we will see how to respond to the Left and Right mouse button clicks.
2. Create MFC SDI Application
First, we have to create a Single Document Interface (SDI) MFC Application project and Name it as MessageHndl. The below video shows how to create it:
By following the steps shown in the above video, you now have a ‘Do nothing’ MFC SDI Application. We will use this application to add code and learn message handling.
3. WM_LBUTTONUP, WM_RBUTTONUP Message Handling
The mouse click is a mix of two events. They are pressing down the button and then releasing it. Here, we will respond to the mouse button release action as it looks like a mouse click. In MFC, BUTTONUP is the best way to track the mouse clicks.
The below video shows adding the handler code for the window messages “ WM_LBUTTONUP”, “ WM_LBUTTONDOWN”. Once handler code skeleton is in hand, we can start writing the code. Now follow the steps explained in the video below:
4. Message Handler Implementation
Once you carry out the steps in the video, Visual Studio IDE adds the code to give default handler functions for the mouse events. Now we will look at these code snippets before adding our own.
4.1 DECLARE_MESSAGE_MAP() Macro
The DECLARE_MESSAGE_MAP macro is added to the header file and it will do the declaration of internal functions and structures written as part of Microsoft Foundation Classes (MFC). These declarations built up by the DECLARE_MESSAGE_MAP macro gives aid for the windows messages handling.
4.2 BEGIN_MESSAGE_MAP & END_MESSAGE_MAP
The Visual Studio IDE adds BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros to the CPP file. Window messages which are handled in the CPP file is wrapped between these macros. “ BEGIN_MESSAGE_MAP” first provides the implementation for the functions declared by the macro “ DECLARE_MESSAGE_MAP”. Then, it populates the array of type “ AFX_MSGMAP_ENTRY”. The population of the array is done by the message map entries added in between Begin and End message map pair.
The macro “ END_MESSAGE_MAP” closes the Message entry initialization. This macro also populates one more structure of type “ AFX_MSGMAP”. This structure has two entries. One is message map entries initialized by the message map pair and another entry is a function pointer which when called returns the “ AFX_MSGMAP” for the base class.
Now, when a message handler does not present in the current class implementation, MFC uses the function pointer to search the handler in the base class. Likewise, it searches the message handler till the very base class. When a handler for the message is found, the MFC Framework calls it.
4.3 Checking the Keyboard Button Status
The below screenshot shows the handler function signature added by the IDE:
Here, we can use the “ Flags” parameter to check button status. For example, we can check whether shift button is down when the user releases the mouse button. Look at the Table below to know the flag constants for the keyboard button status check:
|Flag Constant||Used to Test|
|MK_CONTROL||Sets if the CTRL key is down.|
|MK_MBUTTON||Sets if the middle mouse button is down.|
|MK_RBUTTON||Sets if the right mouse button is down.|
|MK_SHIFT||Set if the SHIFT key is down.|
4.4 Mouse Message Handling Dummy Implementation
The IDE also added the dummy implementation functions in the CPP file for you. The below screenshot shows the implementation added by the class property:
5. Implementing Mouse Message Handling Functions
In the previous section, we reviewed the code added by the Visual Studio. Now, let us add our code and examine the message handling functions.
5.1 Member Variables in MessageHndlView.h
First, we declare the variable m_bluerect of type bool. We will use this variable to alternate the color of the rectangle between blue and green. Next, add a CRect type variable called m_rctUpdateArea. We use this for defining the Update Area of the client window. We will see about this in more detail later. Below is the code snippet:
5.2 Initialize Bounding Box
Have a look at the screenshot below.
First, we initialize the Boolean variable m_bluerect to true (Marked as 1). The OnDraw function (We will discuss the soon) will check this variable and draws the rectangle in blue color when the variable is holding the Boolean true. Next, a bounding box for updating the client area is defined by initializing the data member m_rctUpdateArea (Marked as 2). We will refer this bounding box in the OnDraw function. This helps the OnDraw to draw only a specific region inside the client area. The bounding box is shown as green below and we will draw the rectangle inside this bounding box. In MFC, we usually call this bounding box as “Clipping Region” which marks a specific portion of the area in the client for redrawing.
5.3 Redraw Rectangle In OnDraw
The function “ OnDraw()” gets called by the Windows OS whenever the application requires a redraw. Some well-known examples of its need are below:
- Let us say a user minimized our application and then restored it. Here, redraw of the client area is required. So MFC Framework calls OnDraw function.
- User stacked a notepad application on top our application and then closed it. The area, hidden by the Notepad requires a redraw and MFC needs the OnDraw function.
- The user moved our window from one location to other location in the desktop. Here also our application requires a redraw and hence MFC looks for OnDraw.
Now, look at the code snippet below:
In the above code snippet, first, we define the rectangle which we draw in terms of Top, Left, Bottom and Right (Marked as 1). This is just like how we defined our Clipping Region. After defining the rectangle, the Draw function checks the Boolean flag m_bluerect. In this OnDraw, when the Boolean flag is true, we draw a blue rectangle. Otherwise, we draw a green rectangle (Marked as 2 and 3).
When we compile and run the application at this stage, we always see a blue rectangle. Now, let us write some code for the mouse message handling so that we can change the Boolean flag.
5.4 InvalidateRect and Mouse Message Handling
Now we will set the Boolean member m_bluerect to true in the OnLButtonUp() handler and we set the same Boolean variable as false in the OnRButtonUp() handler (Marked as 3 and 4). Now, when the user clicks the left mouse button, the Boolean is set to true and when they click right mouse button it is set to false.
In both the handler, we are making a call to “ InvalidateRect()” function by supplying the bounding box (Marked as 1 and 2). This means, we are asking windows to redraw portion of the “Client Area” marked by the passed-in rectangle. The call to InvalidateRect will call the OnDraw function. OnDraw first clears the background of the clipping region that is the bounding box and then draws either Blue and Green Rectangle. The screenshot below shows the code snippet:
Note that when we call Invalidate, the full client area gets redrawn. Watch the video below which explains the InvalidateRect and how it works by running the sample with some minor code changes: