Document/View Approach in MFC Revisited:
(Persistence, Serialization, Drawing, Printing)

Drawing and Printing

Framework calls OnDraw(pDC) whenever View needs to be displayed
DC passed to OnDraw() by framework depends on user action:
   WM_PAINT msg (expose events) ==> screen DC
   "Print" or "Print Preview" from menu ==> default printer DC
So to print or make view "permanent", override OnDraw()

Sharing data between Document and View:
   Usually Document should hold the data
   View should display data and control user interaction with it
   So data needs to be exchanged between document and view

Some useful functions:
   GetDocument(): CView member ftn -- gets a ptr to view’s document
        Use to call doc's member ftns & access its data members
   UpdateAllViews(): CDocument ftn -- updates all views of a document
        Call after doc's data has been changed to make view reflect change

Serialization and Persistence

Serialization: Storing a document's data in an archive (file)
Deserialization: Restoring a document's data from an archive
   Both use streaming

CArchive Class: Acts as an I/O stream for a CFile object
   AppWizard sets up CFile objects for use with Carchive
   CFile does the actual I/O (Read, Write, etc.)

CArchive objects:
   process primitive data types 
   and objects derived from CObject (has serialization built in)
CArchive Operators:
     >> Loads (reads) objects or primitive types from archive
     << Stores (writes) objects or primitive types to archive

Important CArchive Member Functions:
   IsLoading(): Determines if archive is being loaded (read)
   IsStoring(): Determines if archive is being stored (written)

Typical sequences of actions with a Doc/View MFC Application:
   User selects File/Open or File/Save from menu (direction)
      Common File Dialog is used to get user's file selection
      CArchive object is set up
   Doc's Serialize() function is called 
      A reference to the CArchive object is passed to document
     (CArchive object contains information on file to be used and action)
   Save/Retrieve primitive data or “serialized” objects within doc’s 
   Serialize() function -- using << or >> operators

Serial0 Example Program:

User can enter a string (dialog box w/ edit box when menu item clicked)
String is displayed where user presses left mouse button
String restored when user exposes client area
String printed in response to "Print" or "Print Prieview"
String and position saved in response to "File / "Save As"
String loaded from file in response to "File / Load"

Build an AppWizard Doc/View MFC, SDI Application (take defaults)
Add an "Enter String" menu item (IDM_STRING) to menu bar
Insert new dialog box w/ IDC_ESTRING edit control 
         (class CSerial0Dlg)
Use ClassWizard to attach member variable to CSerial0Dlg's edit box:      
         CString m_str

In CSerial0Doc class:
  
   Add new public member variables: CPoint m_pt, CString m_str
   
   Use ClassWizard to add OnString() handler for menu item
  
   Edit OnString() to start D-box, set m_str to string entered, update view:
    CStrDlg strdlg;
    strdlg.DoModal();
    m_str=strdlg.m_str;
    UpdateAllViews(NULL);
  
   Add code to OnNewDocument() to display an initial string:
    m_str = "This is a test";
    m_pt = CPoint(0,0);
  
   Add code to Serialize() function to make File Load/Save work:
    // CSerial0Doc serialization
       void CSerial0Doc::Serialize(CArchive& ar)
       {
          if (ar.IsStoring())
          {
             // TODO: add storing code here
             ar<<m_str<<m_pt; //save m_str & m_pt
          }
          else
          {
             // TODO: add loading code here
             ar>>m_str>>m_pt; //retrieve m_Str & m_pt
          }

#include “Serial0Dlg.h”  in the Serial0Doc.cpp file
                   
In CSerial0View class:
  
   Add code to OnDraw() to display string stored in CSerial0Doc class:
  pDC->TextOut(pDoc->m_pt.x,pDoc->m_pt.y,pDoc->m_str);

   Add OnLButtonDown() handler that stores mouse point & forces repaint:
     GetDocument()->m_pt=point;
     Invalidate();

------------------------------------------------------------------------------------------

Collection Classes

Allow grouping of objects

Example:
   CObArray
      Elements can be any CObject-derived objects
      Serialization can be used
      Grows dynamically

Other Collection Classes:
   Arrays: CByteArray, CWordArray, CUintArray, CStringArray, 
                CPtrArray
   Lists: CObList, CPtrList, CstringList
   Maps: CMapWordToOb,  CMapWordToPtr, CMapPtrToPtr, 
              CMapPtrToWord, CMapStringToOb, CMapStringToPtr, 
              CMapStringToString

Modifying Sketch example so sketch can be saved/loaded/printed

Sketches consist of a collection of lines, so:
   Set up a CLine class to hold a line
   And a CObArray class that will hold a collection of CLines

CLine class--

   Member variables:
   CPoint m_ptold;
   CPoint m_pt;

   Member functions:
      Constructor--
      CLine::CLine(CPoint ptFrom, CPoint ptTo)
      {
         m_ptold = ptFrom;
         m_pt = ptTo;
      }


      Draw a line--
      CLine::Draw(CDC* pDC)
      {
         pDC->MoveTo(m_ptold);
         pDC->LineTo(m_pt);
      }

Setting up the Document Class (CSketchDoc)--

   Main data structure: a CObArray to hold the lines:
   CObArray m_oaLines;

   Added functions:

   CLine* GetLine(int nI); // Retrieve line at 
                           // index nI from array
   {
      return (CLine*)m_oaLines[nI];
   }


   int GetLineCount();     // Number of lines in 
                           // array
   {
      return m_oaLines.GetSize();
   }
  
   CLine* AddLine(CPoint ptFrom, CPoint ptTo);
                           // Add line to array
   {
      CLine *pLine = new CLine(ptFrom,ptTo);
      m_oaLines.Add(pLine);
      return pLine;
   }

   Serializing the document--

   Modify CSketchDoc::Serialize() so it serializes each of its CLines
   CSketchDoc::Serialize(CArchive& ar)
   {
      m_oaLines.Serialize(ar);
   }

But now we must add a Serialize() function to the CLine class--
    Information to be saved/retrieved for each line: the endpoints
   void CLine::Serialize(CArchive& ar)
   {
      if (ar.IsStoring())
         ar << m_ptold << m_pt;
      else
         ar >> m_ptold >> m_pt;
   }

And we must set up the CLine class so it can be serialized==>
   DECLARE_SERIAL(CLine)  // macro placed in .h file
                          // right after "class
                          // CLine" declaration
   IMPLEMENT_SERIAL(CLine,CObject,1)  
                         // macro put in .cpp file
                         // right before constructor

Setting up the View class (CSketchView)--

   Add class variables:
    BOOL m_butdn;
    CPoint m_ptPrevPos;

   Add to constructor:
    // TODO: add construction code here
    m_butdn = FALSE;
  
   Add OnLButtonDown() handler and following code:
   // TODO: Add your message handler code here and/or call default
      m_butdn = TRUE;
      m_ptPrevPos = point;

   Add OnLButtonUp() handler and following code:
   // TODO: Add your message handler code here and/or call default
      m_butdn = FALSE;

   Add OnMouseMove() handler and following code:
   // TODO: Add your message handler code here and/or call default
   if(m_butdn)
   {
      CClientDC dc(this);
      CLine *pLine = GetDocument()->AddLine(m_ptPrevPos,point);
      pLine->Draw(&dc);
      m_ptPrevPos = point;
   }

   Add following code to OnDraw():
   // TODO: add draw code for native data here
   int numlines = pDoc->GetLineCount();
   if (numlines>0)
   {
      CLine *ptLine;
      for (int i=0; i<numlines; i++)
      {
         ptLine = pDoc->GetLine(i);
         ptLine->Draw(pDC);
      }
   }

Add #include “Line.h” to each of the following files--
      Line.cpp
      SketchDoc.h
      SketchView.h