CIS Logo SVC Logo

   Computing & Information Systems
   Department

 

Schoology Facebook        Search CIS Site      Tutorials

Software Design Using C++



Single Document Interface with Visual C++ .NET



Drawing Simple Graphics



1) Overview


These directions apply to Visual C++ .NET specifically. The task is to write a Windows app that draws simple graphics. We will use the AppWizard's single document interface. We will place an additional button on the toolbar for the user to click on to add a new drawing on the screen.

2) Using AppWizard


We assume that you have Visual C++ .NET running and have opened an existing solution (used to group several projects together). Begin by making a new project of type "MFC Application". (Use File, New, Project, Visual C++ Projects and then click on MFC Application.) Name the project Drawings and select the Add to Solution option to add this Project to your existing Solution (workspace). Under Application type select Single document. Windows XP users should uncheck Common Control Manifest found under Advanced Features. The default values should be fine for all of the other items. (Note that as discussed under the Dialog-based Interface section, you might want to choose the Statically Linked option instead of the "Shared DLL" option, particularly if you want to use your .exe file under various versions of Windows.) Click on the Finish button.

It is useful to have several windows on the screen. Use View, Solution Explorer if the Solution Explorer is not already visible on the screen. Similarly, use View, Class View as well as View, Resource View to get these windows on the screen. Lastly, use View, Properties Windows to make sure that one is also visible. Click on the Resource view tab. If need be, click on the + in front of Drawings and Drawings.rc to expand what you see. Also click on the + in front of "Dialog" in order to expand this folder.

Make the Drawings project the currently active one. (You can do this by clicking on the Drawings folder in the Solution Explorer and then using Project, Set as Startup Project. An alternative is to right click on the Drawings folder and select Set as Startup Project from the resulting context-sensitive menu.)

3) Change the About Box and Copyright


In the Dialog folder in Resource View double click on IDD_ABOUTBOX. Here is a picture of what we have at this point. Then click on the Copyright line. Change the caption to one word: Freeware. (You can do this by changing the caption field in the Properties window.) You can then close the window used for editing the About Box by clicking on the its x close button.

In Resource View expand the Version folder and double click on VS_VERSION_INFO. Click on LegalCopyright. You can then change the Value field (found in the Properties window) to Freeware. You can also change any other information fields such as Company Name if you wish. You can examine this picture to see what this screen looks like. Do File, Save All. Close the window used to edit the version information.

4) Changing the Menu


Expand the Menu folder in Resource View if necessary. Double click on IDR_MAINFRAME. In the menu editor click on File. We want to delete each item on the File menu except for Exit. Click on each such item and press the Delete key. Even delete the separator bars between menu items, but do not try to delete the blank menu item below Exit. Click on the Edit menu and press Delete in order to remove the entire Edit menu. Leave the View and Help menus alone. Do File, Save All and close the window used to edit the menu bar.

5) Modifying the Toolbar


In Resource View, expand the Toolbar folder if need be. Double click on IDR_MAINFRAME. You should see the standard toolbar. Drag off of the toolbar every button except the print button, the about button (with the question mark on it), and the blank button. Click on this blank button. Then use the drawing tools to draw a blue rightward pointing arrow on the large grid picture of the blank button. (Just click on the blue color and then click on a square in the grid to color that square blue.) This will be your button for displaying the next drawing. While this button is still selected, go to the Properties window and change the ID to ID_BUTTON_NEXT. Also fill in the following as the prompt:


Display the next drawing\nNext

See the lower right portion of this screen shot to see how the above looks in the Properties window. Note that the above changes will allow the user to place the mouse pointer over the button to get information about it. The word Next will be shown near the button when this happens, and "Display the next drawing" will be shown on the status bar at the bottom of the window. You can view the properties of each of the other buttons by clicking on them one at a time. Finally, drag your new blue arrow button to the leftmost position on the toolbar. Do not worry about the fact that there is a new blank button on the toolbar as it will not show up in the completed application. Do File, Save All. Close the window used to edit the toolbar.

6) Add a Message Map


Next, we add a message map function to handle things when the user clicks on your new button. We are going to add this one manually. In the Solution Explorer double click on DrawingsView.h to bring up this file in the editor. Find the class declaration and within this the Attributes section. There will already be one entry in the public section of this. Just below this insert the following private variable (field) which we will use to keep track of how many times the new button is clicked.


private:
   int Count;

Then find the section labeled "Generated Message Map Functions" and add the following to the protected section, right before the line that says DECLARE_MESSAGE_MAP().


//{{AFX_MSG(CDrawingsView)
afx_msg void OnButtonNext();
//}}AFX_MSG

The OnButtonNext function will specify what should be done when your new button is clicked. Now double click on the DrawingsView.cpp in the Solution Explorer. Edit the section at the top that begins with BEGIN_MESSAGE_MAP so that it reads as follows:


BEGIN_MESSAGE_MAP(CDrawingsView, CView)
   //{{AFX_MSG_MAP(CDrawingsView)
   ON_COMMAND(ID_BUTTON_NEXT, OnButtonNext)
   //}}AFX_MSG_MAP
   // Standard printing commands
   ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
   ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
   ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

Note how the added lines associate giving the command of clicking on the button whose ID is ID_BUTTON_NEXT with the OnButtonNext function. We still need to add code for this function. Add the following to the end of the same file:


// CDrawingsView message handlers
void CDrawingsView::OnButtonNext() 
{
   Count++;
   InvalidateRect(NULL, TRUE);
   if (Count >= 4)
      AfxMessageBox("End of sequence of drawings");	
}

Note that the Count variable is used to keep track of what drawing(s) we are to display. When Count is 0 we will display only the initial drawing. When Count is 1 we will display the first 2 drawings. When Count is 2 we will show the first 3 drawings. When Count is 3 we will display all 4 drawings. Finally, if Count is 4 (or greater), the above code pops up a message box that tells us that there are no more drawings. The InvalidateRect function call above causes the OnDraw function to redisplay the window.

We also need to add one line of code to the constructor for CDrawingsView. In the same file, find the constructor and change it to read as follows. This simply initializes the Count variable to zero. Then do File, Save All.


CDrawingsView::CDrawingsView()
{
   Count = 0;
}

7) Drawing Graphics


Find the outline of the OnDraw function in the DrawingsView.cpp file. Change the code for this function to the following:


void CDrawingsView::OnDraw(CDC* pDC)
{
CDrawingsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

CPen NewPen;
CPen * OldPenPtr;
CBrush NewBrush;
CBrush * OldBrushPtr;

NewPen.CreatePen(PS_SOLID, 1, RGB(0, 180, 180));  // aqua color
OldPenPtr = pDC->SelectObject(&NewPen);

if (Count >= 0)
   {
   // Place a message in a rectangle:
   pDC->TextOut(150, 50, "This is a test", 14);
   pDC->MoveTo(100, 10);
   pDC->LineTo(100, 110);
   pDC->LineTo(300, 110);
   pDC->LineTo(300, 10);
   pDC->LineTo(100, 10);
   }
   
if (Count >= 1)
   {
   // Draw a circle:
   NewBrush.CreateSolidBrush(RGB(0, 255, 0));  // to fill with green
   OldBrushPtr = pDC->SelectObject(&NewBrush);
   pDC->Ellipse(350, 10, 550, 210);
   pDC->SetTextColor(RGB(0, 0, 255));  // blue text
   pDC->SetBkMode(TRANSPARENT);
   pDC->SetBkColor(RGB(0, 255, 0));   // green background color
   pDC->TextOut(400, 90, "Circle", 6);
   // Switch back to normal values:
   pDC->SetTextColor(RGB(0, 0, 0));   // black
   pDC->SetBkMode(OPAQUE);
   pDC->SetBkColor(RGB(255, 255, 255));   // white
   pDC->SelectObject(&NewBrush);
   NewBrush.DeleteObject();
   }

// Deselect pen:
pDC->SelectObject(&NewPen);
NewPen.DeleteObject();

if (Count >= 2)
   {
   // Draw a polygon:
   POINT PointArray[6];
   PointArray[0].x = 100;
   PointArray[0].y = 160;
   PointArray[1].x =  50;
   PointArray[1].y = 210;
   PointArray[2].x = 160;
   PointArray[2].y = 260;
   PointArray[3].x = 200;
   PointArray[3].y = 310;
   PointArray[4].x = 300;
   PointArray[4].y = 200;
   PointArray[5].x = 100;
   PointArray[5].y = 160;

   NewPen.CreatePen(PS_SOLID, 2, RGB(255, 0, 0));  // red, double width
   OldPenPtr = pDC->SelectObject(&NewPen);
   NewBrush.CreateSolidBrush(RGB(10, 200, 70));   // a greenish color
   OldBrushPtr = pDC->SelectObject(&NewBrush);
   pDC->Polygon(PointArray, 6);

   pDC->SelectObject(&NewPen);
   NewPen.DeleteObject();
   pDC->SelectObject(&NewBrush);
   NewBrush.DeleteObject();
   }

if (Count >= 3)
   {
   // Draw a smiley face:
   NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));  // blue
   OldPenPtr = pDC->SelectObject(&NewPen);
   NewBrush.CreateSolidBrush(RGB(255, 255, 0));  // to fill with yellow
   OldBrushPtr = pDC->SelectObject(&NewBrush);
   pDC->Ellipse(360, 240, 480, 310);
   pDC->SetPixel(400, 260, RGB(0, 0, 255));   // draw one pixel
   pDC->SetPixel(440, 260, RGB(0, 0, 255));
   pDC->SetPixel(420, 270, RGB(0, 0, 255));
   pDC->Arc(380, 260, 460, 290, 380, 275, 460, 275);
   pDC->SelectObject(&NewPen);
   NewPen.DeleteObject();
   }
}

The comments in the code above and the obvious names of many of the functions will give you a good idea of what the code does. Use Help, Search to look up any details that you need on a particular function. (Hint: use "Visual C++" in the "Filtered by:" box so that you don't see matches for Visual Basic, etc.) It would help to know that for drawing on the screen the upper left corner has coordinates (0, 0) and that the x coordinate increases as you go horizontally across the screen to the right, while the y coordinate increases as you go downward on the screen.

Do File, Save All. Do Build, Build Drawings and fix any minor errors that are noted. Then run your application by clicking on the ! button on the toolbar. When it first starts you should see a rectangle with the first little drawing in it. Clicking on the right arrow button should then add the second drawing, etc. Compare you results to this picture showing all of the items drawn.

8) For Further Practice (Optional)


You might want to modify the above program to draw something of interest to you. You can look up the list of drawing commands by using Help, Search and looking for CDC (the device context class). Double click on the item that says "CDC Members (MFC)". If you know the name of the particular function, such as Ellipse, that you want to look up, you can of course look it up directly.

Related Item:


Single Document Interface with Visual C++ 6.0

Back to the main page for Software Design Using C++

Author: Br. David Carlson with contributions by Br. Isidore Minerd
Last updated: August 27, 2009
Disclaimer