HomeC&C++WainTutorialsSamplesTip&TrickTools


Now I will show how to add the rectangle feature to the line-drawing application.
There is several ways to do that, one could extend the LineClass to handle rectangles as well. If the application was just to have two types of objects this was probably the way to go, but if the application is to handle many types of objects it would be clumsy.
Instead I will have a seperate class for each object types, and have a common base class that all objects must implement.
This could be the base class:
class ObjectBaseClass
{
public:
   virtual void SetEnd(HDC &aDc, POINT aEnd) = 0;
   virtual void Draw(HDC &aDc, bool aMoving = false)  = 0;
};
The functions in ObjectBaseClass are "pure virtual", that is, they do not exist, and classes which inherit must implement them.
The new RectangleClass will then look this way:
class RectangleClass : public ObjectBaseClass
{
public:
   RectangleClass(POINT aStart, COLORREF aColor) :
      Start(aStart),
      End(aStart),
      Color(aColor),
      First(true)
   {}

   void SetEnd(HDC &aDc, POINT aEnd)
   {
      Draw(aDc, true);
      End = aEnd;
      Draw(aDc, true);
   }
   void Draw(HDC &dc, bool aMoving = false);
private:
   POINT Start;
   POINT End;
   COLORREF Color;
   bool First;
};
This is almost the same as LineClass. The Draw function should however draw a rectangle, and not a line.
We have to handle the buttons which select whether to draw a line or a rectangle:
         case DrawRectangleCmd:
            CurrentObject = RectangleObj;
            break;
         case DrawLineCmd:
            CurrentObject = LineObj;
            break;
The next problem is that a vector can only handle one type of object, so we can't have both LineClass objects and RectangleClass objects in the same vector. But we can have ObjectBaseClass pointers in a vector, and a ObjectBaseClass pointer can point at both at bot a Line and a Rectangle. Move over, the ObjectBaseClass has the to functions we need, once we have created the Line or Rectangle.
The vector will then be changed to:
std::vector<ObjectBaseClass *>Objects;
The OnLButtonDown function will need to be changed to:
void OnLButtonDown(HWND aHwnd, int aX, int aY)
{
   POINT P;
   P.x = aX;
   P.y = aY;
   ObjectBaseClass *Object;
   if(CurrentObject == LineObj)
      Object = new LineClass(P, CurrentColor);
   else
      Object = new RectangleClass(P, CurrentColor);
   Objects.push_back(Object);
   IsDrawing = true;
}
Notice that we use new to create the objects, so we need to delete them again before the application is closed:
   size_t i;
   for(i = 0; i < Objects.size(); i++)
      delete Objects[i];
And the OnMouseMove function:
void OnMouseMove(HWND aHwnd, int aX, int aY)
{
   if(IsDrawing)
   {
      POINT P;
      P.x = aX;
      P.y = aY;
      HDC dc = GetDC(aHwnd);
      ObjectBaseClass *Last = Objects.back();
      Last->SetEnd(dc, P);
   }
}
Notice that it does not have to know whether the object to be moved are a line or a rectangle. The only difference from the function from yesterday is that back() returns a pointer and not a reference.
The complete code for the application can be found here