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 >> operatorsSerial0 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