Use the Hint for Efficient Repainting

The last task is to take advantage of the hint so the other views can repaint themselves more efficiently. This involves modifying the CScribbleView class by overriding the OnUpdate function to respond to any hint it receives.

In Scribble Lesson 6, Binding Visual Objects to Code Using WizardBar, you saw how to use WizardBar to connect user-interface objects to their message-handler functions. You can also use WizardBar to override functions inherited from the base class, which are not attached to user-interface objects. The following procedure illustrates this point.

Note   To use WizardBar to override OnUpdate, file ScribbleView.cpp must be open in the text editor.

To add the OnUpdate function to Scribble

  1. Use WizardBar to open ScribbleView.cpp in the text editor.

  2. Click the arrow on the action button, located on the right end of WizardBar.

  3. On the menu, click Add Virtual Function.

    The New Virtual Override dialog box appears.

  4. From the New Virtual Functions list, select OnUpdate.

  5. Click Add and Edit.

  6. Replace the //TODO comments with the following code:
    // The document has informed this view that some data has changed.
    
    if (pHint != NULL)
    {
    if (pHint->IsKindOf(RUNTIME_CLASS(CStroke)))
    {
    // The hint is that a stroke has been added (or changed).
    // So, invalidate its rectangle.
    CStroke* pStroke = (CStroke*)pHint;
    CRect rectInvalid = pStroke->GetBoundingRect();
    InvalidateRect(&rectInvalid);
    return;
    }
    }
    // We can't interpret the hint, so assume that anything might
    // have been updated.
    Invalidate();
    return;
    

    Remember, this function is called by the UpdateAllViews function of CScribbleDoc, which passes it a hint. In this function, the view checks if the hint is a CStroke object. If so, the view gets the bounding rectangle for the stroke and marks it as invalid. This rectangle marks the area that must be redrawn. If the hint isn’t a CStroke object, the view doesn’t know what area was modified, so it invalidates the entire client area as a precaution.

    After a region has been invalidated, Windows sends a WM_PAINT message. The OnPaint member function defined by CView handles this message by calling the virtual OnDraw member function. Consequently, you must modify the OnDraw function to take advantage of the invalidated rectangle when redrawing.

  7. From ClassView, jump to the OnDraw member function in class CScribbleView, and add the following code just after the ASSERT_VALID(pDoc) line:
    // Get the invalidated rectangle of the view, or in the case
    // of printing, the clipping region of the printer DC.
    CRect rectClip;
    CRect rectStroke;
    pDC->GetClipBox(&rectClip);
    
    //Note: CScrollView::OnPaint() will have already adjusted the
    //viewpoint origin before calling OnDraw(), to reflect the
    //currently scrolled position.
    
  8. Then add the following code immediately following the CStroke* pStroke = strokeList.GetNext(pos) line:
    rectStroke = pStroke->GetBoundingRect();
    if (!rectStroke.IntersectRect(&rectStroke, &rectClip))
    continue;
    

    In the OnDraw function, the view first calls the GetClipBox member function of CDC to get the invalidated portion of the client area. Then the view iterates through the list of strokes in the document, calling IntersectRect for each to determine if any part of the stroke lies in the invalidated region. If so, the view asks the stroke to draw itself. Any strokes that don’t intersect the invalidated region don’t have to be redrawn.

Note   This is a good point to compile your changes and test the window updating.

To test your update code

  1. Build and execute Scribble.

  2. Add some lines to the document window.

  3. From the Window menu, click New Window, then click Tile.

  4. Draw in either window and note that the application now correctly tracks the results in both windows.