?? ch22.htm
字號:
<TT>}</TT><TT>void CUser::Set( const CString& szName, const CString& szAddr )</TT><TT>{</TT><TT> m_szName = szName;</TT><TT> m_szAddr = szAddr;</TT><TT>}</TT><TT>CString CUser::GetName() const</TT><TT>{</TT><TT> return m_szName;</TT><TT>}</TT><TT>CString CUser::GetAddr() const</TT><TT>{</TT><TT> return m_szAddr;</TT><TT>}</TT></FONT></PRE><H3><FONT COLOR="#000077"><B>Overriding the <TT>Serialize</TT> Function</B></FONT></H3><P>Every persistent class must implement a <TT>Serialize</TT> member function, whichis called in order to serialize or deserialize an object. The single parameter for<TT>Serialize</TT> is the <TT>CArchive</TT> object used to load or store the object.The version of <TT>Serialize</TT> used by the <TT>CUser</TT> class is shown in Listing22.4; add this function to the <TT>Users.cpp</TT> source file.<H4><FONT COLOR="#000077">TYPE: Listing 22.4. The CUser::Serialize member function.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>void CUser::Serialize( CArchive& ar )</TT><TT>{</TT><TT> if( ar.IsLoading() )</TT><TT> {</TT><TT> ar >> m_szName >> m_szAddr;</TT><TT> }</TT><TT> else</TT><TT> {</TT><TT> ar << m_szName << m_szAddr;</TT><TT> }</TT><TT>}</TT></FONT></PRE><H3><FONT COLOR="#000077"><B>Creating a Serialized Collection</B></FONT></H3><P>You can serialize most MFC collection classes, enabling large amounts of informationto be stored and retrieved easily. For example, you can serialize a <TT>CArray</TT>collection by calling its <TT>Serialize</TT> member function. As with the other MFCtemplate-based collection classes, you cannot use the insertion and extraction operatorswith <TT>CArray</TT>.</P><P>By default, the template-based collection classes perform a bitwise write whenserializing a collection and a bitwise read when deserializing an archive. This meansthat the data stored in the collection is literally written, bit by bit, to the archive.Bitwise serialization is a problem when you use collections to store pointers toobjects. For example, the Customers project uses the <TT>CArray</TT> class to storea collection of <TT>CUser</TT> objects. The declaration of the <TT>CArray</TT> memberis as follows:</P><PRE><FONT COLOR="#0066FF"><TT>CArray<CUser*, CUser*&> m_setOfUsers;</TT></FONT></PRE><P>Because the <TT>m_setOfUsers</TT> collection stores <TT>CUser</TT> pointers, storingthe collection using a bitwise write will only store the current addresses of thecontained objects. This information becomes useless when the archive is deserialized.</P><P>Most of the time, you must implement a helper function to assist in serializinga template-based collection. Helper functions don't belong to a class; they are globalfunctions that are overloaded based on the function signature. The helper functionused when serializing a template is <TT>SerializeElements</TT>. Figure 22.2 showshow you call the <TT>SerializeElements</TT> function to help serialize items storedin a collection.</P><P><A NAME="02"></A><A HREF="02.htm"><B>Figure 22.2.</B> </A><I><BR>The <TT>SerializeElements</TT> helper function.</I></P><P>A version of <TT>SerializeElements</TT> used with collections of <TT>CUser</TT>objects is provided in List- ing 22.5.<H4><FONT COLOR="#000077">TYPE: Listing 22.5. The SerializeElements function.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>void AFXAPI SerializeElements( CArchive& ar,</TT><TT> CUser** pUser,</TT><TT> int nCount )</TT><TT>{</TT><TT> for( int i = 0; i < nCount; i++, pUser++ )</TT><TT> {</TT><TT> if( ar.IsStoring() )</TT><TT> {</TT><TT> (*pUser)->Serialize(ar);</TT><TT> }</TT><TT> else</TT><TT> {</TT><TT> CUser* pNewUser = new CUser;</TT><TT> pNewUser->Serialize(ar);</TT><TT> *pUser = pNewUser;</TT><TT> }</TT><TT> }</TT><TT>}</TT></FONT></PRE><P>The <TT>SerializeObjects</TT> function has three parameters:<UL> <LI>A pointer to a <TT>CArchive</TT> object, as with <TT>Serialize</TT>.<BR> <BR> <LI>The address of an object stored in the collection. In this example, pointers to <TT>CUser</TT> are stored in a <TT>CArray</TT>, so the parameter is a pointer to a <TT>CUser</TT> pointer.<BR> <BR> <LI>The number of elements to be serialized.</UL><P>In this example, when you're serializing objects to the archive, each <TT>CUser</TT>object is individually written to the archive. When you're deserializing objects,a new <TT>CUser</TT> object is created, and that object is deserialized from thearchive. The collection stores a pointer to the new object.<H2><FONT COLOR="#000077"><B>What Is Document/View Serialization?</B></FONT></H2><P>The Document/View architecture uses serialization to save or open documents. Whena document is saved or loaded, the MFC framework in cooperation with the application'sdocument class creates a <TT>CArchive</TT> object and serializes the document toor from storage.</P><P>The <TT>CDocument</TT> member functions required to perform serialization in aDocument/View application are mapped onto the New, Open, Save, and Save As commandsavailable from the File menu. These member functions take care of creating or openinga document, tracking the modification status of a document, and serializing it tostorage.</P><P>When documents are loaded, a <TT>CArchive</TT> object is created for reading,and the archive is deserialized into the document. When documents are saved, a <TT>CArchive</TT>object is created for writing, and the document is written to the archive. At othertimes, the <TT>CDocument</TT> class tracks the current modification status of thedocument's data. If the document has been updated, the user is prompted to save thedocument before closing it.</P><P>The Document/View support for serialization greatly simplifies the work requiredto save and load documents in a Windows program. For a typical program that usespersistent objects, you must supply only a few lines of source code to receive basicsupport for serialization in a Document/View program. The Customers project has abouta page of Document/View source code; most of it is for handling input and outputrequired for the example.</P><P>The routines used by <TT>CArchive</TT> for reading and writing to storage arehighly optimized and have excellent performance, even when you're serializing manysmall data objects. In most cases, it is difficult to match both the performanceand ease of use that you get from using the built-in serialization support offeredfor Document/View applications.<H2><FONT COLOR="#000077"><B>How Are Document/View Applications Serialized?</B></FONT></H2><P>As discussed in Hour 9, "The Document/View Architecture," data storedin a Document/View application is contained by a class derived from <TT>CDocument</TT>.This class also is responsible for controlling the serialization of all data containedby the document class. This includes tracking modifications to the document so thatthe program can display a warning before the user closes an unsaved document.</P><P>There are five phases in a document's life cycle:<UL> <LI>Creating a new document <LI>Modifying the document <LI>Storing, or serializing, the document <LI>Closing the document <LI>Loading, or deserializing, the document</UL><P>You learned about most of these phases in earlier hours. The following sectionsdiscuss how each phase affects document serialization.<H3><FONT COLOR="#000077"><B>Creating a New Document</B></FONT></H3><P>As discussed in Hour 9, you create MDI and SDI documents differently. An MDI applicationcreates a new <TT>CDocument</TT> class for every open document, whereas an SDI programreuses a single document.</P><P>Both SDI and MDI applications call the <TT>OnNewDocument</TT> function to initializea document object. The default version of <TT>OnNewDocument</TT> calls the <TT>DeleteContents</TT>function to reset any data contained by the document. ClassWizard can be used toadd a <TT>DeleteContents</TT> function to your document class. Most applicationscan just add code to <TT>DeleteContents</TT> instead of overriding <TT>OnNewDocument</TT>.<H3><FONT COLOR="#000077"><B>Storing a Document</B></FONT></H3><P>When the user saves a document by selecting File | Save, the <TT>CWinApp::OnFileSave</TT>function is called. This function is almost never overridden; it's a good idea toleave it alone because it calls the <TT>CDocument::OnOpenDocument</TT> function toserialize the document's data. The default version of <TT>OnOpenDocument</TT> createsa <TT>CArchive</TT> object and passes it to the document's <TT>Serialize</TT> memberfunction. Usually, you serialize the data contained in the document in the same waythat other member data was serialized earlier this hour. After the document's datahas been serialized, the dirty bit is cleared, marking the document as unmodified.The steps involved in storing a document are shown in Figure 22.3.</P><P><A NAME="03"></A><A HREF="03.htm"><B>Figure 22.3.</B> </A><I><BR>The major functions called when you store a document.</I></P><P>The default version of <TT>OnOpenDocument</TT> is sufficient for most applications.However, if your application stores data in a different way--for example, in severalsmaller files or in a database--you should override <TT>OnOpenDocument</TT>.</P><P>When the user selects Save As from the File menu, a Common File dialog box collectsfilename information. After the user selects a filename, the program calls the same<TT>CDocument</TT> functions, and the serialization process works as described previously.<H3><FONT COLOR="#000077"><B>Closing a Document</B></FONT></H3><P>When the user closes a document, the MFC Document/View framework calls the documentobject's <TT>OnCloseDocument</TT> member function, as shown in Figure 22.4. The defaultversion of this function checks the document to make sure that no unsaved changesare lost by calling the <TT>IsModified</TT> function. If the user did not modifythe document object, <TT>DeleteContents</TT> is called to free the data stored bythe document, and all views for the document are closed.</P><P><A NAME="04"></A><A HREF="04.htm"><B>Figure 22.4.</B></A> <I><BR>The major functions called when you close a document.</I></P><P>If the user made changes to the document, the program displays a message box thatasks the user whether the document's unsaved changes should be saved. If the userelects to save the document, the <TT>Serialize</TT> function is called. The documentis then closed by calling <TT>DeleteContents</TT> and closing all views for the document.<H3><FONT COLOR="#000077"><B>Loading a Document</B></FONT></H3><P>When you're loading a document, the MFC framework calls the document object's<TT>OnOpenDocument</TT> function. The default version of this function calls the<TT>DeleteContents</TT> member function and then calls <TT>Serialize</TT> to load,or deserialize, the archive. The default version of <TT>OnOpenDocument</TT>, shownin Figure 22.5, is sufficient for almost any application.<H4><FONT COLOR="#000077">Modifying the Document Class</FONT></H4><P>The document class used in the Customers project has one new data member, a <TT>CArray</TT>object that stores a collection of <TT>CUser</TT> pointers representing a customerlist. The document class also has two member functions used to access the array of<TT>CUser</TT> pointers. Add declarations for <TT>m_setOfUsers</TT> and two memberfunctions to the <TT>CCustomersDoc</TT> class, as shown in List- ing 22.6.</P><P><A NAME="05"></A><A HREF="05.htm"><B>Figure 22.5.</B></A> <I><BR>The major functions called when you open a document.</I><H4><FONT COLOR="#000077">TYPE: Listing 22.6. Adding a CArray member variable tothe CCustomersDoc class.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>// Attributes</TT><TT>public:</TT><TT> int GetCount() const;</TT><TT> CUser* GetUser( int nUser ) const;</TT><TT>protected:</TT><TT> CArray<CUser*, CUser*&> m_setOfUsers;</TT></FONT></PRE><P>You should make two other changes to the <TT>CustomersDoc.h</TT> header file.First, because the <TT>CArray</TT> template <TT>m_setOfUsers</TT> is declared interms of <TT>CUser</TT> pointers, you must add an <TT>#include</TT> statement forthe <TT>Users.h</TT> file. Second, you use a version of the <TT>SerializeElements</TT>helper function so you need a declaration of that global function. Add the sourcecode provided in Listing 22.7 to the top of <TT>CustomersDoc.h</TT>.<H4><FONT COLOR="#000077">TYPE: Listing 22.7. Changes to the CustomersDoc.h headerfile.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#include "Users.h"</TT><TT>void AFXAPI SerializeElements( CArchive& ar,</TT><TT> CUser** pUser,</TT><TT> int nCount );</TT></FONT></PRE><P>Because the <TT>CCustomerDoc</TT> class contains a <TT>CArray</TT> member variable,the template collection declarations must be included in the project. Add an <TT>#include</TT>statement to the bottom of the <TT>StdAfx.h</TT> file:</P><PRE><FONT COLOR="#0066FF"><TT>#include "afxtempl.h"</TT></FONT></PRE><H4><FONT COLOR="#000077">Creating a Dialog Box</FONT></H4><P>The dialog box used to enter data for the Customers example is similar to dialogboxes you created for previous examples. Create a dialog box that contains two editcontrols, as shown in Figure 22.6.</P><P><A NAME="06"></A><A HREF="06.htm"><B>Figure 22.6.</B></A> <BR><I>The dialog box used in the Customers sample project.</I></P><P>Give the new dialog box a resource ID of <TT>IDD_USER_DLG</TT>. The two edit controlsare used to add user names and email addresses to a document contained by the <TT>CCustomerDoc</TT>class. Use the values from Table 22.1 for the two edit controls.<H4><FONT COLOR="#000077">Table 22.1. Edit controls contained in the IDD_USER_DLGdialog box.</FONT></H4><P><TABLE BORDER="1"> <TR ALIGN="LEFT" rowspan="1"> <TD ALIGN="LEFT" VALIGN="TOP"><B>Edit Control</B></TD> <TD ALIGN="LEFT" VALIGN="TOP"><B>Resource ID</B></TD> </TR> <TR ALIGN="LEFT" rowspan="1"> <TD ALIGN="LEFT" VALIGN="TOP">Name</TD> <TD ALIGN="LEFT" VALIGN="TOP"><TT>IDC_EDIT_NAME</TT></TD> </TR> <TR ALIGN="LEFT" rowspan="1"> <TD ALIGN="LEFT" VALIGN="TOP">Address</TD> <TD ALIGN="LEFT" VALIGN="TOP"><TT>IDC_EDIT_ADDR</TT></TD> </TR></TABLE></P><P>Using ClassWizard, add a class named <TT>CUsersDlg</TT> to handle the new dialogbox. Add two <TT>CString</TT> variables to the class using the values from Table
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -