CS390-CPP
Lab 1: Programming a Graphic Editor in
C++
in Windows
NOTE:
Here is a Java graphics editor in graph-editor-java.tar.Z. Download it in data.cs.purdue.edu and type "uncompress graph-editor-java.tar.Z; tar -xvf graph-editor-java.tar; javac BoilerDrawMain; java BoilerDrawMain". Read the sources and take ideas of how to implement the features in C++. I think this editor has better model than the one original Visual Studio sources.
This is approximately the grading form that
will be used to grade your project.
The project will be graded
with a demo sometime Thursday Feb 10th or Friday Feb 11th.
Introduction
In this lab you will write a graphical editor using the concepts of
object oriented programming and C++. You will use MFC (Microsoft
Foundation Classes) and Visual Studio.
Step 1. Get Visual Studio C++
To get Visual studio C++, go to the web site http://www.cs.purdue.edu/msdn
and login with your carreer account. Go to "Software" and select Visual
Studio 2008. Then download it and install it in your computer. Purdue
students can download this software without any cost.
Step 2. Download the Initial Files
Download the initial file MyDraw.zip ( MyDraw) into
your computer and unzip it. Then double click in the MyDraw Visual
Studio solution. This will open Visual Studio. Now select the menu
Build->Build Solution.
![welcome welcome](welcome.png)
Once the application is built, select the
menu Debug->Start Debugging.
this will run the initial application. In the application select
Figure->Line to put the editor in NewLine mode. The press the mouse
and drag it to the opposite side of the line and release the mouse. To
create another line select the menu Figure->Line again and repeat
the same mouse sequence. To modify a line, click on the line and drag
the control points. Also, you can select a line and move it. You can
select multiple lines by pressing the mouse in a upper left corner and
dragging the mouse to a lower right corner to create a selection
rectangle. Once multiple lines are selected, you can move all the lines
by moving only one of the lines.
![lines lines](lines.png)
Step 3. Code Organization
The code is organized as follows.
Code generated by the New Project Wizard for MFC Applications:
- MyDraw.h/.cpp : Execution
starts here. Code is initialized etc. This file was generated
automatically by the wizard for MFC applications.
- MyDrawDoc.h/.cpp : Files
that define the document. A document is the data that you are editing,
in this case a drawing.
- MyDrawView.h/.cpp : Files
that define the view of the document. A document may have multiple
views or windows. However, in this case each document has only one
view. You can create a new document (drawing) by selecting File->New in the application.
Code that implements the initial graphic editor. You will need to add
more classes for more functionality.
- ControlPoint.h/.cpp: It
is a class that stores a single coordinate (x,y) and a boolean value
"selected". The control points are used to edit the figures once they
have been created.
- Figure.h/.cpp: It is the
abstract class that is the parent for
Line, Rectangle, Oval, Text etc
(Only the Line class is provided). Figure implements many methods that
these geometrical figures inherit.. A Figure has a list of ControlPoints
that can be modified and provide the position and the size
of the
figures.
- Line.h/Line.cpp: It
inherits from Figure and
implements a Line. During
creation it adds two ControlPoints to
the list, that represent the two extremes of the Line. It also provides a draw() method for drawing the line.
- Drawing.h/.cpp: It stores
a list of all the Figure objects that make the drawing. It also
provides a method that calls the draw method in each figure as well as
a method for handling the mouse events.
The MyDraw application initially creates one MyDrawDoc and a
MyDrawView. The MyDrawDoc has as a member variable a Drawing object
that represents the drawing shown on the screen. The MyDrawView has a
pointer to the document it represents. Also MyDrawView has a OnDraw()
method that is called when the window has to be drawn. This OnDraw
method gets the document and from there it gets the Drawing object and
calls the method pDoc->drawing.draw(pDC); to draw all the figures in
the drawing. Also the MyDrawView defines mouse event call backs such as
OnMouseMove() that call the method pDoc->drawing.OnMouse(this,
nFlags, point); in the Drawing class.
In this project you will mostly add functionality to the Drawing class as well as add new
classes for the different objects. You will also need to learn how to
generate event handlers for the different events using Visual Studio.
At this point see each of the files mentioned above so you can get
familiar with the code. You do not need to understand the files
generated with the Wizard in the first list, but you should understand
the other files in the second list that make the graphic editor.
Step 5. Creating a Rectangle Class
In this step you will build a MyRectangle class so you can get familiar
with Visual Studio and the files that make the Graphic Editor.
1. In the Solution Explorer in the left side, right click on top of the
"Header Files" folder and select Add->Class
![Add Class Add Class](addclass.png)
In Categories: select C++ and in templates select C++ Class and Add.
![add class 2 add class 2](addclass2.png)
Then in the next window type as Class name "MyRectangle" and as base
class "Figure". This is going to add two new files MyRectangle.h and
MyRectangle.cpp to the project. Select "Finish".
![classname classname](classname.png)
You can use the implementation of Line.h
and Line.cpp to came up with
the implementation of MyRectangle.h
and MyRectangle.cpp
Now in MyRectangle.h add the
following:
#pragma once
#include "Figure.h"
class MyRectangle :
public Figure
{
public:
MyRectangle(int x0, int y0, int x1, int y1);
~MyRectangle(void);
// Draw a rectangle using graphic context pDC
void draw(CDC* pDC);
// Return true if rectangle is close to coordinates
(x,y)
bool isCloseTo(int x, int y);
};
and in Rectangle.cpp
add the folowing:
#include "StdAfx.h"
#include "MyRectangle.h"
MyRectangle::MyRectangle(int x0, int y0, int x1, int y1)
:Figure(Figure::FigureType::Rectangle)
{
controlPoints.push_back(new ControlPoint(this,
x0,y0));
controlPoints.push_back(new ControlPoint(this,
x1,y1));
}
MyRectangle::~MyRectangle(void)
{
}
// Draw a rectangle using graphic context pDC
void MyRectangle::draw(CDC* pDC)
{
ControlPoint * p0 = controlPoints.at(0);
ControlPoint * p1 = controlPoints.at(1);
// Find minx, miny, maxx, maxy
int minX =
(p0->getX()<p1->getX())?p0->getX():p1->getX();
int minY =
(p0->getY()<p1->getY())?p0->getY():p1->getY();
int maxX =
(p0->getX()<p1->getX())?p1->getX():p0->getX();
int maxY =
(p0->getY()<p1->getY())?p1->getY():p0->getY();
// Draw rectangle
CPen pen( PS_SOLID, 0, RGB( 0, 0, 0 ) );
CPen* pOldPen = pDC->SelectObject( &pen );
pDC->MoveTo(minX, minY);
pDC->LineTo(maxX, minY);
pDC->LineTo(maxX, maxY);
pDC->LineTo(minX, maxY);
pDC->LineTo(minX, minY);
}
// Return true if rectangle is close to coordinates (x,y)
bool MyRectangle::isCloseTo(int x, int y)
{
ControlPoint * p0 = controlPoints.at(0);
ControlPoint * p1 = controlPoints.at(1);
// Find minx, miny, maxx, maxy
int minX =
(p0->getX()<p1->getX())?p0->getX():p1->getX();
int minY =
(p0->getY()<p1->getY())?p0->getY():p1->getY();
int maxX =
(p0->getX()<p1->getX())?p1->getX():p0->getX();
int maxY =
(p0->getY()<p1->getY())?p1->getY():p0->getY();
// Check if (x,y) is close to any of the borders.
if (Figure::distancePointToLine(x, y, minX, minY,
maxX, minY) < Figure::smallDistance ||
Figure::distancePointToLine(x, y,
maxX, minY, maxX, maxY) < Figure::smallDistance ||
Figure::distancePointToLine(x, y,
minX, maxY, maxX, maxY) < Figure::smallDistance ||
Figure::distancePointToLine(x, y,
minX, minY, minX, maxY) < Figure::smallDistance) {
return true;
}
return false;
}
Now we are going to add a new item in the Figure menu. In the left side
of Visual Studio select the "Resource View" and double click in
IDR_MyDrawTYPE. Then select the Figure->Rectangle and right click on
it to select "Add Event Handler".
![recthandler recthandler](recthandler.png)
In "Message Type" select "COMMAND" and in "Class List:" select
"CMyDrawView". The press "Add and Edit". This will generate the code
for the event handler Figure->Rectangle
![addhandler2 addhandler2](addhandler2.png)
Now in the file CMyDrawView find the method
CMyDrawView::OnFigureRectangle() and add the following code.
void
CMyDrawView::OnFigureRectangle()
{
CMyDrawDoc*
pDoc = GetDocument();
pDoc->drawing.setEditMode(Drawing::NewRectangleMode);
}
This will set the Drawing editor into NewRectangleMode.
In the file Drawing.h find enum EditMode and add the new mode
NewRectangleMode:
// Mode of the Drawing editor.
enum EditMode
{SelectMode, NewLineMode, NewRectangleMode };
In the file Drawing.cpp at the top add:
#include "MyRectangle.h"
and in the method void Drawing::OnMouse(CView * cview, int nFlags,
CPoint point) find the line
if (this->editMode == Drawing::NewLineMode ) {
...
}
and immediately after add the section for the rectangle. This code is
very simmilar to the section for the New Line.
else if (this->editMode == Drawing::NewRectangleMode ) {
// Edit mode
is NewRectangleMode.
// This is
because the user just selected the Figure->Rectangle menu
// Create a
new rectangle.
MyRectangle *
rectangle = new MyRectangle(point.x, point.y, point.x, point.y);
// Add to the
list of figures
this->figures.push_back(rectangle);
// Now switch
to select mode
this->editMode = SelectMode;
// Select only
the last control point of the line
// so dragging
will modify this control point.
this->selectAll(false);
rectangle->selectLast(true);
// Update
previous mouse coordinates
this->previousX = point.x;
this->previousY = point.y;
// Redraw
window. This will call the draw method.
cview->RedrawWindow();
}
else if (this->editMode ==
Drawing::SelectMode) {
Now you should be able to Build->Build Solution and run
Debug->start Debugging
![selectrect selectrect](slectrect.png)
![rects2 rects2](rects2.png)
Here is a tutorial about programming C++ applications in Visual Studio with the MFC. Also you can
google for "Visual Studio C++ MFC tutorial" for more resources.
Step 6. First Part of the project
We will divide this project in two parts. In the frst part you will
implement:
1. Ovals. Add a circle class.
2. Delete Figure
3. Add a new menu to change the color used to draw the figures. Add a
new variable currentColor to the Drawing class and use this color when
drawing the figures. You can either add a new Color Menu with the
multiple color or use the MFC color dialog (google for it).
4. Also implement Groups. You can select a group of figures
and group them into a single figure. Yu can add the oprations Group,
Ungroup, Bring Top, Push Back to change the ordering of the figures.
Step 7. Second Part of the project
In this second part of the project you will add:
1. Copy/Paste
2. Add a Save/Open to save and open the drawing in disk.
3. Add a text figure. When choosing Figure->text, a dialog will show
so the user can type the text to show and it will display it.
The project will be graded Friday February 20th.
We will post the demo times before that day so you may sign up.
To turnin your project zip the directory MyDraw/ and transfer it to lore. Then type
turnin -c cs390lang -p lab1 MyDraw.zip
Additional:
The project will be graded by demostrating the project to the TA. We
will post the demo times later.