MFC and VC++ EXPERIMENTS: Part I

However, there are thousands of existing applications in MFC and they are gradually being ported to DotNet platform. For this reason, during the transition phase, knowledge of legacy libraries and MFC is valuable. Moreover, there are many similarities between C# and MFC.

C#’s ‘syntax and philosophy’ is a mixture of MFC, JDK and VB. Many university courses (in India) continue to prescribe MFC and even Windows SDK in their syllabus for MCA and BE (Computer Science) and corresponding experiments for Practical Examinations. The present tutorial attempts to cover the currently prescribed experiments for the MCA course in Anna University (Tamil Nadu, India), and it is hoped that these will be relevant for students of nearby Universities as well.

Though there are a number of books on MFC and VC++, very few books provide a comprehensive overview of all aspects of the VC++ environment. The MFC library is so vast and some of the more difficult and valuable topics like Winsock, Cryptography and MAPI/TAPI/SAPI (Messaging, Telephony, Speech...API's) are not touched upon even briefly by most of the bulky tomes. By the time they cover the basics, the book would have become unwieldy. There are exceptions. [VC++5 Developers' Guide… by David Bennet and others (Techmedia) and MFC Programming Unleashed with VC++6 by David White & others (Techmedia)]. 

We can develop MFC programs by either using the MFCAppWizard or without using the wizard. Most books on MFC/VC++ begin with the wizard. This could be highly confusing to learners because unlike the VB world, where the automatically generated code is completely hidden from the programmer, files auto-generated in VC++ are exposed and they are forbidding.

Developing GUI programs for the Windows platform using the Microsoft Windows SDK is outdated.

Windows SDK is a C-library for GUI programming from Microsoft and its Hungarian notation, introduced by Charles Simonyi (Hungary born) is another reason why the SDK & MFC codes look so pedantic & cluttered. The book on Windows programming using SDK by Charles Petzold, runs into nearly a thousand pages, much of it being just repetitive WinMain and WinProc (published by Microsoft press…) and its arcane style, has led to the epithet 'Petzoldian' in MFC world. So, this tutorial will not touch upon SDK but will concentrate on MFC alone…

'Peter Nortan's MFC programming' by Rob McGregor, was a unique attempt to present MFC without mixing it much with SDK or wizards. In fact, it is totally free of the wizard-approach. However, it spends too many pages on Controls on screen and is not very useful in practical work. Yeshwant Kanetkar has followed the same approach in his popular book on VC++ and has made the coding even easier. However, though this JDK-like approach is commendable, it is terribly tedious because unlike JDK, there is no Layout Manager in MFC and the syntax for creating the controls directly on the screen is clumsy and laborious. Ready-made ActiveX controls are the most useful items in the Windows world and it is very easy to use them in Wizard-based programs rather than non-wizard programs. For this reason, a very well presented book on VC++5 by Gurewich (Techmedia) covers the subject by using Dialog-based wizard approach. Whatever be the method, the operative part of the code will be same. A list of books on MFC & VC++, which may be referred to by the students after completing this tutorial, has been given at the end. Some of the books are available freely in the web!

We will first see some lessons in plain MFC without using the Wizard and then see their equivalents in Wizard-based programs. Thus, we will get equal exposure to wizard-based as well as non-wizard based programming in VC++. As we are combining the approach of Kanetkar, Gurewich, Holzner and Victor Toth, who are all famous authors on VC++, this tutorial will be using the best from all these authors, with considerable simplification. Emphasis will be on hands-on procedure with just enough of theory. As Martin Fowler puts it "Comprehensiveness is the enemy of comprehensibility". Just as the best way to teach English is not to shove an Oxford or Cambridge dictionary with Rogets Thesaurus and Wren & Martin also, into the hands of a novice learner but teach him the basics and make him learn by using the language, the best way to learn MFC library and its use is by simple examples in small doses. Naturally, many details may be missing but we can refer to the books mentioned for such details, after getting a feel for the subject. Another drawback of Visual programming is that it is so challenging to write on, that too without screen shots! And when a book or article gives plenty of screen shots, it may end up giving nothing else. This tutorial is not meant for merely 'reading' but for hands-on experimentation. Without actually running the program as directed, many aspects may not make much sense.

Let us begin with a very simple experiment to create a window of medium size, display a message and also illustrate the concept of device contexts and mouse-event.

Start VC++ è file è new è
project type=win32 application

 

Once again, file è new è
file type = c++ source file

The standard layout has three areas. On the left side, we have the workspace. At the bottom, we have the output window and on the right side we get the Edit window. If we look carefully, the workspace window has 4 tabs. These are named 'File-View', 'Resource-View', 'Class-View' and 'Info-View'. If we do not load the MSDN library, the Info-view may be missing and it does not matter at present. Even the Resource View tab will not be present, till we create such resources later. Dexterity in switching from one view to another is important in being productive in the VC++ environment and comes only through practice.

We now create our source file in the edit window as given in code 1.

Code 1

DEMO-01       // mouse-event
 

 

#include <afxwin.h>

class myframe  : public CFrameWnd
{
// DECLARATION
private:
   int   a;
   int   b;

public:
   myframe()           // CONSTRUCTOR 
    {
     Create(0,"");
     a=200;         // defining
     b=100;
    }

   
void OnLButtonDown(UINT  f, CPoint  p)
    {
       a=p.x;
       b=p.y;
      Invalidate();  // go to paint
     }

     void OnPaint()   // FUNCTION
     {
      CPaintDC   dc(this);
      dc.TextOut(a,b,"hello");
     }
        DECLARE_MESSAGE_MAP()    
};

BEGIN_MESSAGE_MAP(myframe,CFrameWnd)

    ON_WM_LBUTTONDOWN()
    ON_WM_PAINT()       // MACRO
END_MESSAGE_MAP()

class myapp  :   public CWinApp
{
 public:
    
int   InitInstance()
      {
        myframe*   p;
        p = new myframe;
        p->ShowWindow(1);  // medium size
        m_pMainWnd=p;
        return 1;
      }

 

};

myapp    app;

Let us first compile and execute the program before having a brief explanation of the code. From the menu bar, we go to project è settings and from the combo that appears, select 'Use MFC as Shared Library'.

 

After this, we go to menubar è build è compile.
On successful compiling, menubar
è build è build (for linking) and then menubar è build è execute.

 

We get a window of medium size with the display 'hello' at x=200 (left) and y=100(top), initially. Thereafter, we get the display 'welcome' when we click the mouse.

The previous display is erased. So, CPaintDC can be thought of as 'repaint' context (erasing and painting).

 

If we want 'welcome' display to be shown wherever we click the mouse, without erasing the previous displays, we just comment out Invalidate() and create a local graphics context (CClientDC) as shown in code 2.

 

Code 2

void OnLButtonDown(UINT  f, CPoint  p)
   {
      a=p.x;
      b=p.y;
      // Invalidate();
   CClientDC   dc(this); // local context
   dc.TextOut(a,b,"welcome");
   }

No other change is required. We can recompile and execute the program to get non-erasing context in effect.

We read the code from the last line (i.e.) myapp app; It says that we want the object app of myapp class, which has already been derived from CWinApp and having the function InitInstance. The myapp class makes use of myframe class derived from CFrameWnd.

In all the examples, without using wizard, this file serves as the template. We need not type this each time but can copy and paste and then make the necessary modifications in the myframe class as required. The myframe class is the meat of our application. It has a declaration section, a constructor section, a functions section and then a 'macros' section. Actually, the 'macros' section is very important. For example, if we leave out typing 'ON_WM_PAINT()' in this section, the code will compile but there won’t be any display of the text. So it is better to remember the sequence as follows:

 

1.     declare:     int   a; int  b;
2.     define:      a=100;  b=100;
3.     macro:       ON_WM_PAINT()
4.     function:    void OnPaint()
                 {…     
                       }

That is our first foray into MFC programming. Whatever be the language, in any GUI-based programs, the user can interact with the window through the following five methods:
1. Mouse;
2. Keyboard;
3. Menu;
4. Controls on screen; and
5. Dialog.

Menu, controls and dialog have to be created by the programmer but the very presence of the window makes mouse-events and key-events possible. Just now, we have seen how basic mouse-event can be utilized and we will now see a method of using various keys for getting different things done. We may as well use this lesson to study the various graphics functions available in MFC.


Whenever we need a key-based program, we follow the pattern given in code 3.

Code 3

Declare:  
char k;
Define:    k='z'; 
Macro:     ON_WM_CHAR()
           ON_WM_PAINT()
Function:
     void OnChar(UINT  a, UINT b, UINT c)
     {
       k= (char)   a;
       Invalidate();
     }

    
void OnPaint()
     {
       CPaintDC   dc(this);
if(k=='1') {dc.Rectangle(200,100,500,300);}  
        // etc.
     }

Refer code 4 for the complete code for demo-02.

Code 4
DEMO-02      // key event & graphics

#include <afxwin.h>
class myframe  : public CFrameWnd
{
// DECLARATION
private:
    char      k;
public:  
   myframe()           // CONSTRUCTOR 
    {
     Create(0,"");
      k='z';     
   
}
    void OnChar(UINT a, UINT b, UINT c)
    {
      k=(char)  a;       
// FUNCTION
      Invalidate();  // go to paint
    
     void OnPaint()   
     {
      CPaintDC   dc(this);
if(k=='1') {dc.Rectangle(200,100,500,300);}
if(k=='2') {dc.Ellipse(200,100,500,300);  }
if(k=='3') {dc.MoveTo(200,100);
            dc.LineTo(500,300);}
if(k=='4')
 {dc.Arc(200,100,500,300,500,100,500,300);} 
 if(k=='5')
{dc.Pie(200,100,500,300,500,100,500,300);} 
if(k=='6')
{dc.Chord(200,100,500,300,500,100,500,300);} 
if(k=='7')
{
 POINT   p[3]={ 200,200,300,100,400,200};
dc.Polygon(p,3);
}
     }    
        DECLARE_MESSAGE_MAP()    
};

 

BEGIN_MESSAGE_MAP(myframe,CFrameWnd)
    ON_WM_CHAR()
    ON_WM_PAINT()       // MACRO
END_MESSAGE_MAP()

class  myapp  :   public CWinApp
{
 //as before
};

 

myapp    app;

The bounding rectangle has top-left at (LEFT=200,TOP=100) and bottom-right at (LEFT=500,TOP=300). That gives a width=300 and height=200.

We can draw the ellipse inside this bounding rectangle. For Pie, Chord and Arc, the 5th and 6th parameters are x1,y1 and 7th & 8th parameters are x2,y2. We connect the origin of the bounding rectangle to x1,y1 and x2,y2, respectively. These lines will intersect the ellipse at two points. They define the arc, chord and pie shapes along with the origin.

If our aim is to just study the syntax required for various operations, the key-event method is simple and quick to create. So, we will adopt the same approach to study the syntax for various GDI objects now.

What are the various GDI objects? 
The 4 GDI objects are:
1. Cpen;
2. Cbrush;
3. Cfont; and
4. Cbitmap.


CBitmap is slightly more involved because it requires using the Bitmap Resource editor. We will cover this in a separate lesson to follow. We can illustrate the remaining three objects by key event, as shown in code 5. (This is an unorthodox approach but is enough for testing purpose!)

Code 5
DEMO-03      //
GDI objects(Pen,Brush,Font) 
#include <afxwin.h>
class myframe  : public CFrameWnd
{
// DECLARATION
private:
    char   k;
public:  
  
myframe()           // CONSTRUCTOR 
    {
     Create(0,"");
      k='z';  
MessageBox("key 1 for Pen");
MessageBox("key 2 for Brush");
MessageBox("key 3 for Font");   
    }
    void OnChar(UINT a, UINT b, UINT c)
    {
      k=(char)  a;       
// FUNCTION
      Invalidate();  // go to paint
    
    void OnPaint()
    {
      CPaintDC   dc(this);
if(k=='1')
      {
        CPen     pen1;
pen1.CreatePen(PS_SOLID, 2 , RGB(255,0,0));
//  '2' is thickness
        dc.SelectObject(&pen1);        
       
dc.Rectangle(200,100,500,300);
// x,y,x+w,y+h
// In Java: g.drawRect(x,y,w,h);
      }
if(k=='2')
      {
         CBrush   brush1;
brush1.CreateSolidBrush(RGB(255,0,0));
         dc.SelectObject(&brush1);
         dc.Ellipse(200,100,500,300);
// in Java:  g.fillRect(x,y,w,h);
       }
if(k=='3')
       {
          CFont   font1;
font1.CreateFont(100,20, 
  0,0,0,0,0, 0,0,0,0,0, 0,0,0,
         "Times Roman");
          dc.SelectObject(&font1);
          dc.SetTextColor(RGB(255,0,0));
dc.SetTextColor(RGB(255,0,0));
          dc.TextOut(200,100,"welcome");
       }
     }  // PAINT
     DECLARE_MESSAGE_MAP()
};

 

BEGIN_MESSAGE_MAP(myframe,CFrameWnd)
    ON_WM_CHAR()
    ON_WM_PAINT()       // MACRO
END_MESSAGE_MAP()

class  myapp  :   public CWinApp
{
 //as before
};

myapp    app;

In the above example, there are 14 parameters for creating the required font – height, width, escapement, orientation, weight, italic, underline, strikeout, charset, outprecision, clipprecision, quality, pitch&family and fontname. Except for height, width and fontname, we can simply use 0 for other parameters.

In VB, we usually make use of buttons to generate events as it is most intuitive and we can just drag and drop the controls on the screen. In Java also, the preferred method is by using controls directly on the screen, which is not too difficult to create because of the Layout managers. But in MFC, creation of controls directly on the screen is a very tedious job (as will be illustrated soon) and so the preferred method is by using menu. Such a menu can be created by coding as well as by visual tools. Generally, visual editor for Menu is used. This is known as Menu Resource.

There are other types of resources as well, which we shall delve on in the next article
.




Added on September 14, 2006 Comment

Comments

Post a comment