The Proper Use of Header Files

Chapter 23 - Windows Applications Using the MFC

Visual C++ 6: The Complete Reference
Chris H. Pappas and William H. Murray, III
  Copyright 1998 The McGraw-Hill Companies

A Fourier Series Application with Resources
The next application in this chapter, FOURIER.CPP, will draw a Fourier series waveform in the window’s client area. This application uses two Windows resources: a menu and a dialog box. You may want to refer to Chapter 21 for details on the techniques for creating each of these resources.
As the complexity of each application grows, so does the list of files required for compiling and linking. This application requires a header file named FOURIER.H, a resource header file named FOURIERR.H (note the addition of the extra “R”), a resource script file named FOURIER.RC, and the source code file named FOURIER.CPP.
Enter each file carefully. When all the files have been entered, the application can be compiled and linked. Also, remember to include FOURIER.RC, and FOURIER.CPP in your project file’s list of files needed for the build process.
One header file is used for class information, as you can see in the FOURIER.H file that follows:
class CMainWnd : public CFrameWnd
{
public:
 CMainWnd( );
 afx_msg void OnPaint( );
 afx_msg void OnSize(UINT,int,int);
 afx_msg int  OnCreate(LPCREATESTRUCT cs);
 afx_msg void OnAbout( );
 afx_msg void OnFourierData( );
 afx_msg void OnExit( );
 DECLARE_MESSAGE_MAP( )
};
class CTheApp : public CWinApp
{
public:
 virtual BOOL InitInstance( );
};

class CFourierDataDialog : public CDialog
{
public:
 CFourierDataDialog(CWnd
* pParentWnd=NULL)
                   : CDialog(“FourierData”,pParentWnd)
                   {  }
 virtual void OnOK( );
};
Another header file contains the traditional ID values needed by menus and dialog boxes. This file is named FOURIERR.H.
#define IDM_FOUR   100
#define IDM_ABOUT  110
#define IDM_EXIT   120
#define IDD_TERMS  200
#define IDD_TITLE  201
The resource script file, FOURIER.RC, for this example includes a description for a menu and two dialog box descriptions. The dialog box descriptions are for a simple About box and a data entry dialog box.
//Microsoft Developer Studio generated resource script.
//
#include “fourierr.h”

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include “windows.h”
#undef APSTUDIO_HIDDEN_SYMBOLS
#include “afxres.h”
/////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

/////////////////////////////////////////////////////////////
//
// Menu
//

FOURIERMENU MENU DISCARDABLE
BEGIN
 POPUP “Fourier Data”
 BEGIN
   MENUITEM “Fourier Data...”, IDM_FOUR
   MENUITEM “Fourier About...”, IDM_ABOUT
   MENUITEM “Exit”, IDM_EXIT
 END
END
/////////////////////////////////////////////////////////////
//
// Dialog
//

ABOUTBOX DIALOG DISCARDABLE  14, 22, 200, 75
STYLE WS_POPUP | WS_CAPTION
CAPTION “About Box”
BEGIN
 CTEXT “A Fourier Series Waveform”,-1,30,5,144,8
 CTEXT “A MFC Application”,-1,30,17,144,8
 CTEXT “By William H. Murray and Chris H. Pappas”,
       -1,28,28,144,8
 CTEXT “(c) Copyright 1998",201,68,38,83,8
 DEFPUSHBUTTON   ”OK",IDOK,84,55,32,14,WS_GROUP
END
FOURIERDATA DIALOG DISCARDABLE  74, 21, 142, 70
STYLE WS_POPUP | WS_CAPTION
CAPTION “Fourier Data”
BEGIN
 LTEXT “Title: ”,-1,6,5,28,8,NOT WS_GROUP
 EDITTEXT IDD_TITLE,33,1,106,12
 LTEXT “Number of terms: ”,-1,6,23,70,8,NOT WS_GROUP
 EDITTEXT IDD_TERMS,76,18,32,12
 PUSHBUTTON “OK”,IDOK,25,52,24,14
 PUSHBUTTON “Cancel”,IDCANCEL,89,53,28,14
END

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE DISCARDABLE
BEGIN
 “resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
 ”#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
 “#include ”"windows.h""\r\n"
 “#undef APSTUDIO_HIDDEN_SYMBOLS\r\n”
 “#include ”"afxres.h""\r\n"
 “\0"
END

3 TEXTINCLUDE DISCARDABLE
BEGIN
 ”\r\n"
 “\0"
END

#endif    // APSTUDIO_INVOKED

#endif    // English (U.S.) resources
/////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//

/////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED
The source code file, FOURIER.CPP, is slightly more complicated than the previous example because it must handle a menu and two dialog box resources. See if you can find this additional code as you examine the following listing:
//
//  fourier.cpp
//  Drawing A Fourier Series with the use of
//  the MFC library.
//  Copyright (c) William H. Murray and Chris H. Pappas, 1998
//

#include <afxwin.h>
#include <string.h>
#include <math.h>
#include “fourierR.h”   // resource IDs
#include “fourier.h”

int m_cxClient,m_cyClient;
char mytitle[80]="Title";
int nterms=1;
CTheApp theApp;

CMainWnd::CMainWnd( )
{
 Create((AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,
        LoadCursor(NULL,IDC_CROSS),
        (HBRUSH) (GetStockObject(WHITE_BRUSH)),NULL)),
        “Fourier Series Application with the MFC”,
        WS_OVERLAPPEDWINDOW,rectDefault,NULL,"FourierMenu");
}

void CMainWnd::OnSize(UINT,int x,int y)
{
 m_cxClient=x;
 m_cyClient=y;
}

void CMainWnd::OnPaint( )
{
 CPaintDC dc(this);
 static DWORD dwColor[9]={RGB(0,0,0),        //black
                          RGB(245,0,0),      //red
                          RGB(0,245,0),      //green
                          RGB(0,0,245),      //blue
                          RGB(245,245,0),    //yellow
                          RGB(245,0,245),    //magenta
                          RGB(0,245,245),    //cyan
                          RGB(127,127,127),  //gray
                          RGB(245,245,245)}; //white

 int i,j,ltitle,ang;
 double y,yp;
 CBrush newbrush;
 CBrush* oldbrush;
 CPen newpen;
 CPen* oldpen;
 // create a custom drawing surface
 dc.SetMapMode(MM_ISOTROPIC);
 dc.SetWindowExt(500,500);
 dc.SetViewportExt(m_cxClient,-m_cyClient);
 dc.SetViewportOrg(m_cxClient/20,m_cyClient/2);

 ang=0;
 yp=0.0;

 newpen.CreatePen(BS_SOLID,2,RGB(0,0,0));
 oldpen=dc.SelectObject(&newpen);
  
 // draw x & y coordinate axes
 dc.MoveTo(0,240);
 dc.LineTo(0,-240);
 dc.MoveTo(0,0);
 dc.LineTo(400,0);
 dc.MoveTo(0,0);
 // draw actual Fourier waveform
 for (i=0; i<=400; i++) {
   for (j=1; j<=nterms; j++) {
     y=(150.0/((2.0*j)-1.0))*sin(((j*2.0)-1.0)*0.015708*ang);
     yp=yp+y;
   }
   dc.LineTo(i,(int) yp);
   yp-=yp;
   ang++;
 }

 // prepare to fill interior of waveform newbrush.
 newbrush.CreateSolidBrush(dwColor[7]);
 oldbrush=dc.SelectObject(&newbrush);
 dc.ExtFloodFill(150,10,dwColor[0],FLOODFILLBORDER);
 dc.ExtFloodFill(300,-10,dwColor[0],FLOODFILLBORDER);

 // print waveform title
 ltitle=strlen(mytitle);
 dc.TextOut(200-(ltitle*8/2),185,mytitle,ltitle);

 // delete brush objects
 dc.SelectObject(oldbrush);
 newbrush.DeleteObject( );
}

int CMainWnd::OnCreate(LPCREATESTRUCT)
{
 UpdateWindow( );
 return (0);
}
void CMainWnd::OnAbout( )
{
 CDialog about(“AboutBox”,this);
 about.DoModal( );
}

void CFourierDataDialog::OnOK( )
{
 GetDlgItemText(IDD_TITLE,mytitle,80);
 nterms=GetDlgItemInt(IDD_TERMS,NULL,0);
 CDialog::OnOK( );
}

void CMainWnd::OnFourierData( )
{
 CFourierDataDialog dlgFourierData(this);
 if (dlgFourierData.DoModal( )==IDOK) {
   InvalidateRect(NULL,TRUE);
   UpdateWindow( );
 }
};

void CMainWnd::OnExit( )
{
 DestroyWindow( );
}

BEGIN_MESSAGE_MAP(CMainWnd,CFrameWnd)
 ON_WM_PAINT( )
 ON_WM_SIZE( )
 ON_WM_CREATE( )
 ON_COMMAND(IDM_ABOUT,OnAbout)
 ON_COMMAND(IDM_FOUR,OnFourierData)
 ON_COMMAND(IDM_EXIT,OnExit)
END_MESSAGE_MAP( )

BOOL CTheApp::InitInstance( )
{
 m_pMainWnd=new CMainWnd( );
 m_pMainWnd->ShowWindow(m_nCmdShow);
 m_pMainWnd->UpdateWindow( );
 return TRUE;
}
The FOURIER.H Header File
As the code segment below shows, CMainWnd now contains several function declarations and a message map. The member functions include OnPaint( ), OnSize( ), OnCreate( ), OnAbout( ), OnFourierData( ), and OnExit( ). The afx_msg keyword is used instead of virtual. The OnPaint( ) member function is found in the CWnd class. The CWnd class is overridden by the CMainWnd class. This allows the client area of the window to be altered.
afx_msg void OnPaint( );
afx_msg void OnSize(UINT,int,int);
afx_msg int  OnCreate(LPCREATESTRUCT cs);
afx_msg void OnAbout( );
afx_msg void OnFourierData( );
afx_msg void OnExit( );
The OnPaint( ) function is automatically called when a WM_PAINT message is sent to a CMainWnd object by Windows or the application. The OnSize( ) function is called whenever a WM_SIZE message is generated by a change in the size of the window. This information will be useful for scaling graphics to the window size. The OnCreate( ) function points to a structure that contains information about the window being created. This structure contains information on the size, style, and other aspects of the window. The functions OnAbout( ), OnFourierData( ), and OnExit( ) are user-defined functions that respond to WM_COMMAND messages. WM_COMMAND messages are generated when the user selects an option from a menu or dialog box.
DECLARE_MESSAGE_MAP is used again to state that the class overrides the handling of certain messages. (See the body of the application.) Recall that this technique is more space efficient than the use of virtual functions.
The MFC library supports regular and modal dialog boxes with the CDialog class. For very simple dialog boxes such as About boxes, the MFC can be used directly. For data entry dialog boxes, however, the class will have to be derived. The dialog box for this example will permit the user to enter an optional graph title and an integer for the number of harmonics to be drawn in the window. The CFourierDataDialog class is derived from the CDialog foundation class. Modal dialog boxes must be dismissed before other actions can be taken in an application, as shown in the following portion of code:
class CFourierDataDialog : public CDialog
{
public:
 CFourierDataDialog(CWnd
* pParentWnd=NULL)
                   : CDialog(“FourierData”,pParentWnd)
                   {  }
 virtual void OnOK( );
};
In a derived modal dialog class, member variables and functions can be added to specify the behavior of the dialog box. Member variables can also be used to save data entered by the user or to save data for display. Classes derived from CDialog require their own message maps, with the exception of the OnInitDialog( ), OnOK( ), and OnCancel( ) functions.
In this simple example, the CfourierDataDialog( ) constructor supplies the name of the dialog box, “FourierData,” and the name of the dialog box’s owner. The parent window is the owner for this modal dialog box.
The dialog box will actually return data to the application when the user clicks on the OK dialog box button. If either the OK or the Cancel button is clicked, the dialog box closes and is removed from the screen. When the dialog box closes, the member functions access their member variables to retrieve information entered by the user. Dialog boxes requiring initialization can override the OnInitDialog( ) member function for this purpose.
The Resource Files
The FOURIERR.H resource header file and the FOURIER.RC resource script file are used by the resource compiler to produce a single compiled Windows resource.
The FOURIERR.H resource header file contains five identification values. IDM_FOUR, IDM_ABOUT, and IDM_EXIT are used for menu selection choices, while IDD_TERMS and IDD_TITLE are for the data entry dialog box.
The resource script file also contains a description of the application’s menu and dialog boxes. The menu is shown in Figure 23-3. Compare the menu title and features to the text used to create the menu in the resource file.
Figure 23-3: The menu is created for the FOURIER.CPP application
This application also uses two dialog boxes. Figure 23-4 shows the About dialog box for this application.
Figure 23-4: The About box for the FOURIER.CPP application
Figure 23-5 shows the data entry dialog box for this application.
Figure 23-5: The data entry dialog box for the FOURIER.CPP application
Take a minute to compare the text file for each dialog box with the actual screen figures. Remember that the dialog box resources used the resource editor to construct both dialog boxes.
The FOURIER.CPP Source Code File
The complexity of the application file for this example has increased greatly because of the inclusion of menus and dialog boxes. Other features, which you might want to include in your own programs, have also been added. In the following sections, you’ll see how to:
  Determine the size of the current window
  Draw and fill an object in the window
  Select a new cursor
  Set a new viewport and origin for drawing
  Set the background color
Let’s examine these features as they appear in the program.
Creating a Custom CMainWnd Class
Using AfxRegisterWndClass to create a registration class can customize the CMainWnd class. A registration class has many fields, but four are easily altered: style, cursor, background, and the Minimize icon.
The following small piece of code shows the syntax for changing the cursor to a stock cross shape (IDC_CROSS) and setting the brush that paints the background to a WHITE_BRUSH:
CMainWnd::CMainWnd( )
{
 Create((AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,
       LoadCursor(NULL,IDC_CROSS),
       (HBRUSH) GetStockObject(WHITE_BRUSH),NULL)),
       “ Fourier Series Application with the MFC”,
       WS_OVERLAPPEDWINDOW,rectDefault,NULL,"FourierMenu");
}
Also note that the menu name is identified in the Create( ) member function.
Determining the Window’s Current Size
The OnSize( ) member function returns the size of the current client window. A WM_SIZE message is generated whenever the window is resized. As shown here, the current window size is saved in two variables, m_cxClient and m_cyClient:
void CMainWnd::OnSize(UINT,int x,int y)
{
 m_cxClient=x;
 m_cyClient=y;
}
These values will be used to scale the graphics the application draws to fit the current window’s dimensions.
Drawing the Fourier Waveform
In order to prevent the scaling problems described in the previous example, a scalable drawing surface is created. You may wish to review the purpose of these functions in Chapter 21.
As shown in the following code, the mapping mode is changed to MM_ISOTROPIC with the SetMapMode( ) function. The MM_ISOTROPIC mapping mode uses arbitrary drawing units.
dc.SetMapMode(MM_ISOTROPIC);
The next line of code shows the window’s extent set to 500 units in both the x and y directions:
dc.SetWindowExt(500,500);
This simply means that the x and y axes will always have 500 units, regardless of the size of the window. The viewport extent is set to the currently reported window size, as shown here:
dc.SetViewportExt(m_cxClient,-m_cyClient);
In this case, you will see all 500 units in the window.
  Note Using a negative value when specifying the y viewport extent forces y to increase in the upward direction.
As the following code shows, the viewport origin is set midway on the y axis a short distance (a fifth of the length) from the left edge of the x axis:
dc.SetViewportOrg(m_cxClient/20,m_cyClient/2);
Next, x and y coordinate axes are drawn in the window. Compare the values shown here to the axes shown in screen shots later in this section:
// draw x & y coordinate axes
dc.MoveTo(0,240);
dc.LineTo(0,-240);
dc.MoveTo(0,0);
dc.LineTo(400,0);
dc.MoveTo(0,0);
The technique for drawing the Fourier wave, shown below, uses two for loops. The i variable controls the angle used by the sine function, and the j variable holds the value for the current Fourier harmonic. Each point plotted on the screen is a summation of all the Fourier harmonics for a given angle. Thus, if you request that the application draw 1,000 harmonics, approximately 400,000 separate calculations will be made.
// draw actual Fourier waveform
for (i=0; i<=400; i++)
{
 for (j=1; j<=nterms; j++)
 {
   y=(150.0/((2.0
*j)-1.0))*sin(((j*2.0)-1.0)*0.015708*ang);
   yp=yp+y;
 }
 dc.LineTo(i,(int) yp);
 yp-=yp;
 ang++;
}
The LineTo( ) function is used to connect each calculated point, forming a waveform drawn with a solid line. This waveform will have its interior region filled with a gray color by the ExtFloodFill( ) function. The ExtFloodFill( ) function requires the coordinates of a point within the fill region and the bounding color that the figure was drawn with. The FLOODFILLBORDER parameter fills to the boundary color. You can determine these values from the following code:
// prepare to fill interior of waveform newbrush.
 newbrush.CreateSolidBrush(dwColor[7]);
 oldbrush=dc.SelectObject(&newbrush);
 dc.ExtFloodFill(150,10,dwColor[0],FLOODFILLBORDER);
 dc.ExtFloodFill(300,-10,dwColor[0],FLOODFILLBORDER);
Before the figure is completed, a title is printed in the window and the brush object is deleted, as shown here:
// print waveform title
ltitle=strlen(mytitle);
dc.TextOut(200-(ltitle
*8/2),185,mytitle,ltitle);

// delete brush objects
dc.SelectObject(oldbrush);
newbrush.DeleteObject( );
Remember that all objects drawn within the client area will be scaled to the viewport. This program eliminates the sizing problem of earlier examples and requires only a little additional coding.
The About Dialog Box
About boxes are very easy to create and implement. About boxes are used to communicate information about the program, the program’s designers, the copyright date, and so on.
A modal dialog box is created when the user selects the Fourier About... option from the application’s menu. The OnAbout( ) command handler requires only a few lines of code:
void CMainWnd::OnAbout( )
{
 CDialog about(“AboutBox”,this);
 about.DoModal( );
}
The constructor for CDialog uses the current window as the parent window for the object. The this pointer is typically used here and refers to the currently used object. The DoModal( ) member function is responsible for drawing the About box in the client area. When the OK button in the About box is clicked, the box is removed and the client area is repainted.
The Data Entry Dialog Box
Dialog boxes that allow user input require a bit more programming than simple About boxes do. A data input dialog box can be selected from the application’s menu by selecting Fourier Data.…
An illustration of this dialog box was shown earlier. The user is permitted to enter a chart title and an integer representing the number of Fourier harmonics to draw. If the user clicks on the OK button, the data entry dialog box is removed from the window and the client area is updated, as shown in the following portion of code:
void CMainWnd::OnFourierData( )
{
 CFourierDataDialog dlgFourierData(this);
 if (dlgFourierData.DoModal( )==IDOK)
 {
   InvalidateRect(NULL,TRUE);
   UpdateWindow( );
 }
};
CFourierDataDialog was derived from CDialog in the header file, FOURIER.H, as discussed earlier. Notice, however, that it is at this point in the application that data is retrieved. The user entered this data in the dialog box. Here is a portion of code that returns this information when the dialog box’s OK push button is clicked:
void CFourierDataDialog::OnOK( )
{
 GetDlgItemText(IDD_TITLE,mytitle,80);
 nterms=GetDlgItemInt(IDD_TERMS,NULL,0);
 CDialog::OnOK( );
}
The GetDlgItemText( ) function returns chart title information to mytitle in the form of a string. The dialog box location for this information is identified by IDD_TITLE. Integer information can be processed in a similar manner with the GetDlgItemInt( ) function. Its dialog box identification value is IDD_TERMS, and the integer retrieved by the function is returned to the variable nterms. The second parameter is used to report translation errors, but is not used in this application. If the third parameter is nonzero, a check will be made for a signed number. In this application, only positive numbers are possible.
Responding to OnExit( )
The final application menu option is Exit. Exit will destroy the client window by calling the DestroyWindow( ) function:
void CMainWnd::OnExit( )
{
 DestroyWindow( );
}
This application menu option gives the user a method of exiting the application without using the system menu.
The Message Map
Two classes are specified in BEGIN_MESSAGE_MAP: CMainWnd and CFrameWnd. CMainWnd is the target class, and CFrameWnd is a class based on CWnd. The ON_WM_PAINT( ) function handles all WM_PAINT messages and directs them to the OnPaint( ) member function. ON_WM_SIZE( ) handles WM_SIZE messages and directs them to the OnSize( ) member function. The ON_WM_CREATE( ) function handles WM_CREATE messages and directs them to the OnCreate( ) member function. There is an ON_COMMAND( ) function for each application menu item. Message information on menu items is processed and then returned to the appropriate member function. Here is the message map for this example:
BEGIN_MESSAGE_MAP(CMainWnd,CFrameWnd)
 ON_WM_PAINT( )
 ON_WM_SIZE( )
 ON_WM_CREATE( )
 ON_COMMAND(IDM_ABOUT,OnAbout)
 ON_COMMAND(IDM_FOUR,OnFourierData)
 ON_COMMAND(IDM_EXIT,OnExit)
END_MESSAGE_MAP( )
As mentioned in an earlier example, the use of message maps has eliminated the need for error-prone switch/case statements.
Running FOURIER
Compile the application with the Project utility. When the FOURIER application is executed, a default waveform is drawn in the client area. A default value of one harmonic produces a sine wave, as shown in Figure 23-6. Figure 23-7 shows ten harmonics, and Figure 23-8 shows 50 harmonics.
Figure 23-6: The default graph for the FOURIER.CPP application
Figure 23-7: Ten Fourier harmonics
Figure 23-8: Fifty Fourier harmonics
As the number of harmonics increases, the figure drawn in the client area will approach a perfect square wave. You can experiment with various values and note how the drawing time increases for very large numbers of harmonics.

Books24x7.com, Inc 2000 –  


Visual C++ 6(c) The Complete Reference
Visual Studio 6: The Complete Reference
ISBN: B00007FYGA
EAN: N/A
Year: 1998
Pages: 207

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net