Define a Hint for Scribble

When a stroke is added to a drawing in Scribble, the rectangular region that contains the new stroke is the only area that needs to be updated; the remainder of the drawing can be left alone. Therefore, a logical choice for a hint in Scribble is the bounding rectangle of the new stroke.

Instead of creating a separate class to represent the hint, it’s more convenient to pass a CStroke pointer as a hint. Store the bounding rectangle for each stroke in the CStroke object itself, so that it can be quickly referred to by OnUpdate to determine which area of the window needs to be repainted.

The following procedure assumes you have your Scribble project file (Scribble.dsw) open in the workspace.

To define bounding rectangles for strokes

  1. From ClassView, jump to the definition for class CStroke.

  2. In the Attributes section, add the following code, just after the m_pointArray declaration:
    protected:
    CRect m_rectBounding;  // smallest rect that surrounds all
      // of the points in the stroke
    public:
    CRect& GetBoundingRect() { return m_rectBounding; }
    

    The protected member variable m_rectBounding is a CRect object storing the bounding rectangle, and the public member function GetBoundingRect allows the rectangle to be retrieved by the view.

  3. Now search ScribbleDoc.cpp for the IMPLEMENT_SERIAL macro and change the schema number parameter to 2.
    IMPLEMENT_SERIAL( CStroke, CObject, 2 )
    

    This version of Scribble changes what’s stored in a CStroke object by adding a new member variable. Changing the schema number distinguishes strokes saved by this version of Scribble from those of other versions.

  4. Go to the second CStroke constructor (the one that initializes the pen width) and add the following line:
    m_rectBounding.SetRectEmpty();
    

    This initializes the bounding rectangle to an empty rectangle in the constructor.

  5. Jump to the CStroke Serialize function and add the following line just after the first if condition:
    ar << m_rectBounding;
    

    This stores the m_rectBounding member variable in the archive.

  6. Add its code pair just after the else branch:
    ar >> m_rectBounding;
    

    This reads the m_rectBounding member variable from the archive.

In the next procedure, you’ll add a helper function, FinishStroke. This function calculates the bounding rectangle, which is needed for smart repainting.

To add the FinishStroke helper function

  1. From ClassView, point at the CStroke class icon and click the right mouse button.

  2. From the pop-up menu, click Add Function.

    The Add Member Function dialog box appears.

  3. In the Function Type box, type the return type (in this case, void).

  4. In the Function Declaration box, type the following:
    FinishStroke()
    
  5. In the Access area, select Public.

  6. Click OK.

    ClassWizard adds the declaration to the header file, creates a starter definition in the implementation file, and jumps you to the body of the definition so you can begin typing your application-specific code.

  7. Type the following code to fill in the function definition for FinishStroke:
    if( m_pointArray.GetSize() == 0 )
    {
    m_rectBounding.SetRectEmpty();
    return;
    }
    CPoint pt = m_pointArray[0];
    m_rectBounding = CRect( pt.x, pt.y, pt.x, pt.y );
    
    for (int i=1; i < m_pointArray.GetSize(); i++)
    {
    // If the point lies outside of the accumulated bounding
    // rectangle, then inflate the bounding rect to include it.
    pt = m_pointArray[i];
    m_rectBounding.left   = min(m_rectBounding.left, pt.x);
    m_rectBounding.right  = max(m_rectBounding.right, pt.x);
    m_rectBounding.top    = min(m_rectBounding.top, pt.y);
    m_rectBounding.bottom = max(m_rectBounding.bottom, pt.y);
    }
    
    // Add the pen width to the bounding rectangle.  This is needed
    // to account for the width of the stroke when invalidating
    // the screen.
    m_rectBounding.InflateRect(CSize(m_nPenWidth, m_nPenWidth));
    return;
    

The FinishStroke member function calculates the bounding rectangle for a stroke. In this function, the stroke object iterates through its array of points, testing the location of each; if a point falls outside the current bounding rectangle, the stroke object enlarges the bounding rectangle just enough to contain it. Then the bounding rectangle is expanded on each side by the width of the pen.