Creating the ATL Polygon Project

Chapter 21 - Procedure-oriented Windows Applications

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

Creating a Pie Chart Application
A pie chart is a useful business application that also allows you to incorporate many of the resources studied in the last chapter into a presentation-quality program. This particular pie chart will use a menu, an About dialog box, and a data entry dialog box for user input. All three items, you might recall, were designed in the previous chapter. The data entry dialog box will prompt the user to enter up to ten numbers that define the size of each pie wedge. These integer numbers are then scaled in order to make each pie slice proportional in the 360-degree pie chart. Slices are colored in a sequential manner. The sequence is defined by the programmer and contained in the global array lColor[]. The program also allows the user to enter a title for the pie chart, which is centered below the pie figure. You may wish to continue the development of this example by adding a legend, label, or value for each pie slice.
Before compiling and linking, you will need to enter four separate files: PIE.H, PIE.RC, PIE.C, and PIE.CUR. The cursor was created with the resource editor, too.
Start this project by creating a new project file named PIE.DSP. If you are entering the code from the following listings, you will simply open several empty text files with the Project | Add | Files… menu selection, and name them appropriately.
Here is the PIE.H header file containing unique identification numbers for menu, dialog, and other resource items:
#define IDM_ABOUT    10
#define IDM_INPUT    20
#define IDM_EXIT     30

#define DM_TITLE    160
#define DM_P1       161
#define DM_P2       162
#define DM_P3       163
#define DM_P4       164
#define DM_P5       165
#define DM_P6       166
#define DM_P7       167
#define DM_P8       168
#define DM_P9       169
#define DM_P10      170
The PIE.RC resource script file defines a menu and two dialog boxes (See Chapter 20 for additional details). See if you can identify this information in the following listing:
//Microsoft Developer Studio generated resource script.
//
#include “resource.h”

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

/////////////////////////////////////////////////////////////
#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
/////////////////////////////////////////////////////////////
//
// Cursor
//

PIECURSOR CURSOR DISCARDABLE “pie.cur”

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

PIEMENU MENU DISCARDABLE
BEGIN
 POPUP “Pie_Chart_Data”
 BEGIN
   MENUITEM “About...”, IDM_ABOUT
   MENUITEM “Input...”, IDM_INPUT
   MENUITEM “Exit”,     IDM_EXIT
 END
END
/////////////////////////////////////////////////////////////
//
// Dialog
//

ABOUTDLGBOX DIALOG DISCARDABLE  50, 300, 180, 84
STYLE DS_MODALFRAME|WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU
CAPTION “About”
FONT 8, “MS Sans Serif”
BEGIN
 CTEXT “Microsoft C Pie Chart Program”,-1,3,29,176,10
 CTEXT “by William H. Murray and Chris H. Pappas”,-1,3,16,
        176,10
 PUSHBUTTON “OK”,IDOK,74,51,32,14
END
PIEDLGBOX DIALOG DISCARDABLE  93, 37, 195, 159
STYLE DS_MODALFRAME|WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU
CAPTION “Pie Chart Data”
FONT 8, “MS Sans Serif”
BEGIN
 GROUPBOX “Chart Title:”,100,5,3,182,30,WS_TABSTOP
 GROUPBOX “Pie Wedge Sizes:”,101,3,34,187,95,WS_TABSTOP
 LTEXT “Title: ”,-1,10,21,30,8
 EDITTEXT DM_TITLE,40,18,140,12
 LTEXT “Wedge #1: ”,-1,10,50,40,8,NOT WS_GROUP
 LTEXT “Wedge #2: ”,-1,10,65,40,8,NOT WS_GROUP
 LTEXT “Wedge #3: ”,-1,10,80,40,8,NOT WS_GROUP
 LTEXT “Wedge #4: ”,-1,10,95,40,8,NOT WS_GROUP
 LTEXT “Wedge #5: ”,-1,10,110,40,8,NOT WS_GROUP
 LTEXT “Wedge #6: ”,-1,106,50,40,8,NOT WS_GROUP
 LTEXT “Wedge #7: ”,-1,106,65,40,8,NOT WS_GROUP
 LTEXT “Wedge #8: ”,-1,106,80,40,8,NOT WS_GROUP
 LTEXT “Wedge #9: ”,-1,106,95,40,8,NOT WS_GROUP
 LTEXT “Wedge #10:”,-1,102,110,45,8,NOT WS_GROUP
 EDITTEXT DM_P1,55,45,30,12
 EDITTEXT DM_P2,55,60,30,12
 EDITTEXT DM_P3,55,75,30,12
 EDITTEXT DM_P4,55,90,30,12
 EDITTEXT DM_P5,55,105,30,12
 EDITTEXT DM_P6,150,44,30,12
 EDITTEXT DM_P7,150,61,30,12
 EDITTEXT DM_P8,150,76,30,12
 EDITTEXT DM_P9,149,91,30,12
 EDITTEXT DM_P10,149,106,30,12
 PUSHBUTTON “OK”,IDOK,39,135,24,14
 PUSHBUTTON “Cancel”,IDCANCEL,122,136,34,14
END

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

1 TEXTINCLUDE DISCARDABLE
BEGIN
 “resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
 ”#include “”pie.h""\r\n"
 “#define APSTUDIO_HIDDEN_SYMBOLS\r\n”
 “#include ”"windows.h""\r\n"
 “#undef APSTUDIO_HIDDEN_SYMBOLS\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
Remember that the PIE.RC file is simply the text file equivalent to the menu and dialog boxes that were developed by the resource editors and discussed in the previous chapter.
The PIE.C source code is the last listing in this group of files. The length of this file has grown when compared to previous source code files because of the dialog box procedures. However, as you study the listing, you should still be able to locate elements of the SWP.C template.
/*
*  PIE.C
*  A Pie Chart Application with Resources
*  Copyright (c) William H. Murray and Chris H. Pappas, 1998
*/

#include <windows.h>
#include <string.h>
#include <math.h>
#include “pie.h”

#define radius      180
#define maxnumwedge 10
#define pi          3.14159265359
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
BOOL CALLBACK AboutDlgProc(HWND,UINT,WPARAM,LPARAM);
BOOL CALLBACK PieDlgProc(HWND,UINT,WPARAM,LPARAM);

char szProgName[]="ProgName";
char szApplName[]="PieMenu";
char szCursorName[]="PieCursor";

char szTString[80]="(pie chart title area)";
unsigned int iWedgesize[maxnumwedge]={5,20,10,15};
long lColor[maxnumwedge]={0x0L,0xFFL,0xFF00L,0xFFFFL,0xFF0000L,
                         0xFF00FFL,0xFFFF00L,0xFFFFFFL,
                         0x8080L,0x808080L};

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPreInst,
                  LPSTR lpszCmdLine,int nCmdShow)
{
 HWND hWnd;
 MSG  lpMsg;
 WNDCLASS wcApp;

 wcApp.lpszClassName=szProgName;
 wcApp.hInstance    =hInst;
 wcApp.lpfnWndProc  =WndProc;
 wcApp.hCursor      =LoadCursor(hInst,szCursorName);
 wcApp.hIcon        =LoadIcon(hInst,szProgName);
 wcApp.lpszMenuName =szApplName;
 wcApp.hbrBackground=GetStockObject(WHITE_BRUSH);
 wcApp.style        =CS_HREDRAW|CS_VREDRAW;
 wcApp.cbClsExtra   =0;
 wcApp.cbWndExtra   =0;
 if (!RegisterClass (&wcApp))
   return 0;
 hWnd=CreateWindow(szProgName,"Pie Chart Application",
                   WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,
                   CW_USEDEFAULT,CW_USEDEFAULT,
                   CW_USEDEFAULT,(HWND)NULL,(HMENU)NULL,
                   (HANDLE)hInst,(LPSTR)NULL);
 ShowWindow(hWnd,nCmdShow);
 UpdateWindow(hWnd);
 while (GetMessage(&lpMsg,0,0,0))
 {
   TranslateMessage(&lpMsg);
   DispatchMessage(&lpMsg);
 }
 return(lpMsg.wParam);
}

BOOL CALLBACK AboutDlgProc(HWND hdlg,UINT messg,
                          WPARAM wParam,LPARAM lParam)
{
 switch (messg)
 {
   case WM_INITDIALOG:
     break;
   case WM_COMMAND:
     switch (wParam)
     {
       case IDOK:
         EndDialog(hdlg,TRUE);
         break;
       default:
         return FALSE;
     }
     break;
   default:
     return FALSE;
 }
 return TRUE;
}
BOOL CALLBACK PieDlgProc(HWND hdlg,UINT messg,
                        WPARAM wParam,LPARAM lParam)
{
 switch (messg)
 {
   case WM_INITDIALOG:
     return FALSE;
   case WM_COMMAND:
     switch (wParam)
     {
       case IDOK:
         GetDlgItemText(hdlg,DM_TITLE,szTString,80);
         iWedgesize[0]=GetDlgItemInt(hdlg,DM_P1,NULL,0);
         iWedgesize[1]=GetDlgItemInt(hdlg,DM_P2,NULL,0);
         iWedgesize[2]=GetDlgItemInt(hdlg,DM_P3,NULL,0);
         iWedgesize[3]=GetDlgItemInt(hdlg,DM_P4,NULL,0);
         iWedgesize[4]=GetDlgItemInt(hdlg,DM_P5,NULL,0);
         iWedgesize[5]=GetDlgItemInt(hdlg,DM_P6,NULL,0);
         iWedgesize[6]=GetDlgItemInt(hdlg,DM_P7,NULL,0);
         iWedgesize[7]=GetDlgItemInt(hdlg,DM_P8,NULL,0);
         iWedgesize[8]=GetDlgItemInt(hdlg,DM_P9,NULL,0);
         iWedgesize[9]=GetDlgItemInt(hdlg,DM_P10,NULL,0);
         EndDialog(hdlg,TRUE);
         break;
       case IDCANCEL:
         EndDialog(hdlg,FALSE);
         break;
       default:
         return FALSE;
     }
     break;
   default:
     return FALSE;
 }
 return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT messg,
                        WPARAM wParam,LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 HBRUSH hBrush;
 static FARPROC lpfnAboutDlgProc;
 static FARPROC lpfnPieDlgProc;
 static HWND hInst1,hInst2;
 static int xClientView,yClientView;

 unsigned int iTotalWedge[maxnumwedge+1];
 int i,iNWedges;

 iNWedges=0;
 for (i=0;i<maxnumwedge;i++) {
   if(iWedgesize[i]!=0) iNWedges++;
 }

 iTotalWedge[0]=0;

 for (i=0;i<iNWedges;i++)
   iTotalWedge[i+1]=iTotalWedge[i]+iWedgesize[i];
 switch (messg)
 {
   case WM_SIZE:
     xClientView=LOWORD(lParam);
     yClientView=HIWORD(lParam);
     break;
   case WM_CREATE:
     hInst1=((LPCREATESTRUCT) lParam)->hInstance;
     hInst2=((LPCREATESTRUCT) lParam)->hInstance;
     lpfnAboutDlgProc=MakeProcInstance(AboutDlgProc,
                                       hInst1);
     lpfnPieDlgProc=MakeProcInstance(PieDlgProc,hInst2);
     break;
   case WM_COMMAND:
     switch (wParam)
     {
       case IDM_ABOUT:
         DialogBox(hInst1,"AboutDlgBox",hWnd,
                   lpfnAboutDlgProc);
         break;
       case IDM_INPUT:
         DialogBox(hInst2,"PieDlgBox",
                   hWnd,lpfnPieDlgProc);
         InvalidateRect(hWnd,NULL,TRUE);
         UpdateWindow(hWnd);
         break;
       case IDM_EXIT:
         SendMessage(hWnd,WM_CLOSE,0,0L);
         break;
       default:
         break;
     }
     break;
   case WM_PAINT:
     hdc=BeginPaint(hWnd,&ps);
     SetMapMode(hdc,MM_ISOTROPIC);
     SetWindowExtEx(hdc,500,500,NULL);
     SetViewportExtEx(hdc,xClientView,-yClientView,NULL);
     SetViewportOrgEx(hdc,xClientView/2,yClientView/2,NULL);
     if (xClientView > 200)
       TextOut(hdc,strlen(szTString)*(-8/2),
               240,szTString,strlen(szTString));

     for(i=0;i<iNWedges;i++) {
       hBrush=CreateSolidBrush(lColor[i]);
       SelectObject(hdc,hBrush);
       Pie(hdc,-200,200,200,-200,
          (int)(radius*cos(2*pi*iTotalWedge[i]/
                iTotalWedge[iNWedges])),
          (int)(radius*sin(2*pi*iTotalWedge[i]/
                iTotalWedge[iNWedges])),
          (int)(radius*cos(2*pi*iTotalWedge[i+1]/
                iTotalWedge[iNWedges])),
          (int)(radius*sin(2*pi*iTotalWedge[i+1]/
                iTotalWedge[iNWedges])));
     }


     ValidateRect(hWnd,NULL);
     EndPaint(hWnd,&ps);
     break;
   case WM_DESTROY:
     PostQuitMessage(0);
     break;
   default:
     return(DefWindowProc(hWnd,messg,wParam,lParam));
 }
 return(0);
}
In the next sections, we’ll look at the important components that make up the complete pie project.
The Project File
Use the Project utility from within the integrated environment to build a project file for this application. Include the PIE.C and PIE.RC files in the project’s file list.
The PIE.H Header File
The header file PIE.H contains identification information for various menu and dialog items. Additionally, note the ten unique identification numbers, which represent the ten values for wedge sizes. The user eventually enters these values.
The PIE.RC Resource File
The resource file PIE.RC contains information in script form for the pointer (PieCursor), menu (PieMenu), and two dialog boxes (AboutDlgBox and PieDlgBox). Figure 21-17 shows the About box and Figure 21-18 shows the data entry dialog box.
Figure 21-17: The About box for the PIE.C application
Figure 21-18: The data entry dialog box for PIE.C
The design of both of these dialog boxes was discussed in the previous chapter. The resource editor created this composite resource script file as each resource was added to the project. When using the resource editor to add dialog boxes, you must have a fairly clear idea of how you want to represent various data fields and so on before starting the design. The control values are used to determine the position, size, and so on of dialog box items. The resource editor calculates these values. If you are entering this program, it will be easiest for you just to type this resource file as it appears in the listing.
The PIE.C Source Code
The C source code for PIE.C allows the user to develop a pie chart with as many as ten slices. An application will allow the user to input the data on pie-slice sizes directly to a dialog box. In addition to data on pie sizes, the user may enter the title of the pie chart. Don’t let the size of this code listing scare you; much of the code you see is an extension of the SWP.C template code developed in the first example of this chapter. It would be a good idea to compare the SWP.C and PIE.C code at this time and discover the exact differences in the listings. This example concentrates on the new concepts for the application by extracting each important feature from the listing.
Dialog box information is processed with the case IDOK statement under the PieDlgProc. When the user selects the data entry item (a dialog box) from the program’s menu, they will be allowed to enter a pie chart title and the data for up to ten pie slices. This data is accepted when the user selects the OK push button. The title is returned as a text string with the GetDlgItemText( ) function. Numeric information is returned with the GetDlgItemInt( ) function. This function translates the “numeric” string information entered by the user into an integer that can be a signed or unsigned number. The GetDlgItemInt( ) function requires four parameters. The handle and ID number are self-explanatory. The third parameter, which is NULL in this case, is used to flag a successful conversion. The fourth parameter is used to indicate signed and unsigned numbers. In this case, a zero states that the dialog box is returning unsigned numbers. These numbers are saved in the global array iWedgesize[ ] for future use.
The major work in this application is done in the WindowProc( ) function. Various pieces of information and data are sent as messages and examined by the five case statements. Study the code and make sure you can find these “message” case statements: WM_SIZE, WM_CREATE, WM_COMMAND, WM_PAINT, and WM_DESTROY.
Determining the size of the client or application window is achieved with the help of WM_SIZE. Windows sends a message to WM_SIZE any time the window is resized. In this case, the size will be returned in two variables, xClientView and yClientView. This information will be used by WM_PAINT to scale the pie chart to the window.
The program’s instance handle is obtained and saved as hInst1 and hInst2 when processing messages to WM_CREATE. These values are used by the MakeProcInstance( ) function to create an instance thunk for each dialog box procedure or function. This is necessary because each dialog box procedure is a far procedure. The address returned by MakeProcInstance( ) points to a fixed portion of memory called the instance thunk. Two are required in this case because two dialog box procedures are being used.
Dialog boxes can be opened with messages sent to WM_COMMAND. Notice that WM_COMMAND contains three case statements. IDM_ABOUT is the ID for the About Box procedure, while IDM_INPUT is the ID for the data entry dialog box. IDM_EXIT allows a graceful exit from the application.
The routines for actually drawing the pie wedges are processed under WM_PAINT.
The mapping mode is changed to MM_ISOTROPIC from MM_TEXT. The default mapping mode is MM_TEXT. When in the MM_TEXT mapping mode, drawings are made in “pixel” coordinates with point 0,0 in the upper-left corner of the window. This is why the SINE.C example remained unchanged as the number of pixels changed in the client area.
SetMapMode(hdc,MM_ISOTROPIC);
SetWindowExtEx(hdc,500,500,NULL);
SetViewportExtEx(hdc,xClientView,-yClientView,NULL);
SetViewportOrgEx(hdc,xClientView/2,yClientView/2,NULL);
Table 21-4 shows additional mapping modes available under Windows.
Table 21-4: Mapping Modes for Windows Applications
Value
Meaning
MM_ANISOTROPIC
Maps one logical unit to an arbitrary physical unit. The x and y axes are scaled.
MM_HIENGLISH
Maps one logical unit to 0.001 inch. Positive y is up.
MM_HIMETRIC
Maps one logical unit to 0.01 millimeter. Positive y is up.
MM_ISOTROPIC
Maps one logical unit to an arbitrary physical unit;  x and y unit lengths are equal.
MM_LOENGLISH
Maps one logical unit to 0.01 inch. Positive y points up.
MM_LOMETRIC
Maps one logical unit to 0.1 millimeter. Positive y points up.
MM_TEXT
Maps one logical unit to one pixel. Positive y points down. This is the default mode.
MM_TWIPS
Maps one logical unit to 1/20 of a printer’s point.
Positive
y points up.
MM_ISOTROPIC allows you to select the extent of both the x and y axes. The mapping mode is changed by calling the function SetMapMode( ). When the function SetWindowExt( ) is called with both parameters set to 500, the height and width of the client or application areas are equal. These are logical sizes that Windows adjusts (scales) to fit the physical display device. The display size values are used by the SetViewportExt( ) function. The negative sign for the y coordinate specifies increasing y values from the bottom of the screen. It should be no surprise that these are the values previously obtained under WM_SIZE.
For this example, the pie chart will be placed on a traditional x,y coordinate system, with the center of the chart at 0,0. The SetViewportOrgEx( ) function is used for this purpose.
The pie chart title is printed to the screen using the coordinates for the current mapping mode. The program centers the title on the screen by estimating the size of the character font and knowing the string length. For really small windows, the title is not printed.
if (xClientView > 200)
 TextOut(hdc,strlen(szTString)
*(-8/2),
         240,szTString,strlen(szTString));
Before actually discussing how the pie wedges are plotted, let’s return to the beginning of the WndProc procedure in order to gain an understanding of how the wedges are scaled to fit a complete circle. There are several pieces of code that are very important.
This code determines how many wedges the user has requested:
iNWedges=0;
for (i=0;i<maxnumwedge;i++) {
 if(iWedgesize[i]!=0) iNWedges++;
}
It is assumed that there is at least one wedge of some physical size, so the array iWedgesize[ ] can be scanned for the first zero value. For each nonzero value returned, iNWedges will be incremented. Thus, when leaving this routine, iNWedges will contain the total number of wedges for this plot.
A progressive total on wedge size values will be returned to the iTotalWedge[ ] array. These values will help determine where one pie slice ends and the next begins. For example, if the user entered 5, 10, 7, and 20 for wedge sizes, iTotalWedge[ ] would contain the values 0, 5, 15, 22, and 42. Study the following code to make sure you understand how these results are achieved:
iTotalWedge[0]=0;
for (i=0;i<iNWedges;i++)
 iTotalWedge[i+1]=iTotalWedge[i]+iWedgesize[i];
The values contained in iTotalWedge[ ] are needed in order to calculate the beginning and ending angles for each pie wedge. You might recall that the Pie( ) function accepts nine parameters. The first parameter is the handle, and the next four specify the coordinates of the bounding rectangle. In this case, for the mapping mode chosen, they are -200, 200, 200, and -200. The remaining four parameters are used to designate the starting x,y pair and the ending x,y pair for the pie arc. To calculate x values, the cosine function is used, and to calculate y values, the sine function is used. For example, the first x position is determined by multiplying the radius of the pie by the cosine of 2*pi*iTotalWedge[0]. The 2*pi value is needed in the conversion of degrees to radians. The y value is found with the sine function in an identical way. Those two values serve as the x,y starting coordinates for the first slice. The ending coordinates are found with the same equations, but using the next value in iTotalWedge[ ]. In order to scale each of these points to make all slices proportional and fit a 360-degree pie, each coordinate point is divided by the grand total of all individual slices. This total is the last number contained in iTotalWedge[ ]. Observe how this calculation is achieved in the next piece of code:
for(i=0;i<iNWedges;i++) {
 hBrush=CreateSolidBrush(lColor[i]);
 SelectObject(hdc,hBrush);
 Pie(hdc,-200,200,200,-200,
    (int)(radius
*cos(2*pi*iTotalWedge[i]/
          iTotalWedge[iNWedges])),
    (int)(radius
*sin(2*pi*iTotalWedge[i]/
          iTotalWedge[iNWedges])),
    (int)(radius
*cos(2*pi*iTotalWedge[i+1]/
          iTotalWedge[iNWedges])),
    (int)(radius
*sin(2*pi*iTotalWedge[i+1]/
          iTotalWedge[iNWedges])));
}
In order to draw and fill all slices, a loop is used. This loop will index through all iNWedge values.
Figure 21-19 shows the default pie chart plot, and Figure 20 shows a unique pie chart application.
Figure 21-19: The default pie chart drawn with PIE.C
Figure 21-20: A unique pie chart created with PIE.C

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