⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch13.htm

📁 VC 21天 学习VC 的好东西
💻 HTM
📖 第 1 页 / 共 5 页
字号:
10:     }
11:     else
12:         // No records, return NULL
13:         return NULL;
14: }</PRE>
<P>
<H4>Serializing the Record Set</H4>
<P>When filling in the Serialize functionality in the document class, there's little
to do other than pass the CArchive object to the object array's Serialize function,
just as you did on Day 10.</P>
<P>When reading data from the archive, the object array will query the CArchive object
to determine what object type it needs to create and how many it needs to create.
The object array will then create each object in the array and call its Serialize
function, passing the CArchive object to each in turn. This enables the objects in
the object array to read their own variable values from the CArchive object in the
same order that they were written.</P>
<P>When writing data to the file archive, the object array will call each object's
Serialize function in order, passing the CArchive object (just as when reading from
the archive). This allows each object in the array to write its own variables into
the archive as necessary.</P>
<P>For the sample application, edit the document class's Serialize function to pass
the CArchive object to the object array's Serialize function, as in Listing 13.18.</P>
<P>
<H4>Listing 13.18. THE CSerializeDoc.Serialize FUNCTION.</H4>
<PRE>1: void CSerializeDoc::Serialize(CArchive&amp; ar)
2: {
3:     // Pass the serialization on to the object array
4:     m_oaPeople.Serialize(ar);
5: }</PRE>
<P>
<H4>Cleaning Up</H4>
<P>Now you need to add the code to clean up the document once the document is closed
or a new document is opened. This consists of looping through all objects in the
object array and deleting each and every one. Once all the objects are deleted, the
object array can be reset when you call its RemoveAll function.</P>
<P>To implement this functionality in your sample application, add an event-handler
function to the document class on the DeleteContents event message using the Class
Wizard. When editing the function, add the code in Listing 13.19.</P>
<P>
<H4>LISTING 13.19. THE CSerializeDoc.DeleteContents FUNCTION.</H4>
<PRE> 1: void CSerializeDoc::DeleteContents()
 2: {
 3:     // TODO: Add your specialized code here and/or call the base class
 4: 
 5:     ///////////////////////
 6:     // MY CODE STARTS HERE
 7:     ///////////////////////
 8: 
 9:     // Get the number of lines in the object array
10:     int liCount = m_oaPeople.GetSize();
11:     int liPos;
12: 
13:     // Are there any objects in the array?
14:     if (liCount)
15:     {
16:         // Loop through the array, deleting each object
17:         for (liPos = 0; liPos &lt; liCount; liPos++)
18:             delete m_oaPeople[liPos];
19:         // Reset the array
20:         m_oaPeople.RemoveAll();
21:     }
22: 
23:     ///////////////////////
24:     // MY CODE ENDS HERE
25:     ///////////////////////
26: 
27:     CDocument::DeleteContents();
28: }</PRE>


<BLOCKQUOTE>
	<P>
<HR>
<STRONG>NOTE:</STRONG> One thing to keep in mind when writing this code is that you need
	to cast the pointer to the view as a pointer of the class of your view object. The
	GetNextView function returns a pointer of type CView, so you will not be able to
	call any of your additions to the view class until you cast the pointer to your view
	class. Casting the pointer tells the compiler that the pointer is really a pointer
	to your view object class and thus does contain all the functions that you have added.
	If you don't cast the pointer, the compiler will assume that the view object does
	not contain any of the functions that you have added and will not allow you to compile
	your application.
<HR>


</BLOCKQUOTE>

<H4>Opening a New Document</H4>
<P>When a new document is started, you need to present the user with an empty form,
ready for new information. To make that empty record ready to accept new information,
you need to add a new record into the object array, which is otherwise empty. This
results in only one record in the object array. Once the new record is added to the
array, you must modify the view to show that a new record exists; otherwise, the
view will continue to display the last record edited from the previous record set
(and the user will probably wonder why your application didn't start a new record
set).</P>
<P>To implement this functionality, you will need to edit the OnNewDocument function
in your document class. This function is already in the document class, so you do
not need to add it through the Class Wizard. The first thing that you do in this
function is add a new record to the object array. Once the new record is added, you
need to get a pointer to the view object. You use the GetFirstViewPosition function
to get the position of the view object. Using the position returned for the view
object, you can use the GetNextView function to retrieve a pointer to the view object.
Once you have a valid pointer, you can use it to call a function that you will create
in the view class to tell the view to refresh the current record information being
displayed in the form.</P>
<P>Locate the OnNewDocument function in the document class source code, and add the
code in Listing 13.20. Before you will be able to compile your application, you will
need to add the NewDataSet function to the view class.</P>
<P>
<H4>LISTING 13.20. THE CSerializeDoc.OnNewDocument FUNCTION.</H4>
<PRE> 1: BOOL CSerializeDoc::OnNewDocument()
 2: {
 3:     if (!CDocument::OnNewDocument())
 4:         return FALSE;
 5: 
 6:     // TODO: add reinitialization code here
 7:     // (SDI documents will reuse this document)
 8: 
 9:     ///////////////////////
10:     // MY CODE STARTS HERE
11:     ///////////////////////
12: 
13:     // If unable to add a new record, return FALSE
14:     if (!AddNewRecord())
15:         return FALSE;
16: 
17:     // Get a pointer to the view
18:     POSITION pos = GetFirstViewPosition();
19:     CSerializeView* pView = (CSerializeView*)GetNextView(pos);
20:     // Tell the view that it's got a new data set
21:     if (pView)
22:         pView-&gt;NewDataSet();
23: 
24:     ///////////////////////
25:     // MY CODE ENDS HERE
26:     ///////////////////////
27: 
28:     return TRUE;
29: }</PRE>
<P>When opening an existing data set, you don't need to add any new records, but
you still need to let the view object know that it needs to refresh the record being
displayed for the user. As a result, you can add the same code to the OnOpenDocument
function as you added to the OnNewDocument, only leaving out the first part where
you added a new record to the object array.</P>
<P>Add an event-handler function to the document class for the OnOpenDocument event
using the Class Wizard. Once you add the function, edit it adding the code in Listing
13.21.</P>
<P>
<H4>LISTING 13.21. THE CSerializeDoc.OnOpenDocument FUNCTION.</H4>
<PRE> 1: BOOL CSerializeDoc::OnOpenDocument(LPCTSTR lpszPathName)
 2: {
 3:     if (!CDocument::OnOpenDocument(lpszPathName))
 4:         return FALSE;
 5: 
 6:     // TODO: Add your specialized creation code here
 7: 
 8:     ///////////////////////
 9:     // MY CODE STARTS HERE
10:     ///////////////////////
11: 
12:     // Get a pointer to the view
13:     POSITION pos = GetFirstViewPosition();
14:     CSerializeView* pView = (CSerializeView*)GetNextView(pos);
15:     // Tell the view that it's got a new data set
16:     if (pView)
17:         pView-&gt;NewDataSet();
18: 
19:     ///////////////////////
20:     // MY CODE ENDS HERE
21:     ///////////////////////
22: 
23:     return TRUE;
24: }</PRE>
<P>
<H3><A NAME="Heading10"></A>Adding Navigating and Editing Support in the View Class</H3>
<P>Now that you've added support for the record set to your document class, you need
to add the functionality into the view class to navigate, display, and update the
records. When you first designed your view class, you placed a number of controls
on the window for viewing and editing the various data elements in each record. You
also included controls for navigating the record set. Now you need to attach functionality
to those controls to perform the record navigation and to update the record with
any data changes the user makes.</P>
<P>Because of the amount of direct interaction that the form will have with the record
object--reading variable values from the record and writing new values to the record--it
makes sense that you want to add a record pointer to the view class as a private
variable. For your example, add a new member variable to the view class, specify
the type as CPerson*, give it a name such as m_pCurPerson, and specify the access
as private. Next, edit the view source code file and include the header file for
the person class, as in Listing 13.22.</P>
<P>
<H4>LISTING 13.22. INCLUDING THE CUSTOM OBJECT HEADER IN THE VIEW CLASS SOURCE CODE.</H4>
<PRE> 1: // SerializeView.cpp : implementation of the CSerializeView class
 2: //
 3: 
 4: #include &quot;stdafx.h&quot;
 5: #include &quot;Serialize.h&quot;
 6: 
 7: #include &quot;Person.h&quot;
 8: #include &quot;SerializeDoc.h&quot;
 9: #include &quot;SerializeView.h&quot;
10: 
11: #ifdef _DEBUG
12: .
13: .
14: .</PRE>
<P>
<H4>Displaying the Current Record</H4>
<P>The first functionality that you will want to add to the view class is the functionality
to display the current record. Because this functionality will be used in several
different places within the view class, it makes the most sense to create a separate
function to perform this duty. In this function, you get the current values of all
the variables in the record object and place those values in the view class variables
that are attached to the controls on the window. The other thing that you want to
do is get the current record number and the total number of records in the set and
display those for the user so that the user knows his or her relative position within
the record set.</P>
<P>In your sample application, add a new member function, specify the function type
as void, give the function a name that makes sense, such as PopulateView, and specify
the access as private. In the function, get a pointer to the document object. Once
you have a valid pointer to the document, format the position text display with the
current record number and the total number of records in the set, using the GetCurRecordNbr
and GetTotalRecords functions that you added to the document class earlier. Next,
if you have a valid pointer to a record object, set all the view variables to the
values of their respective fields in the record object. Once you set the values of
all of the view class variables, update the window with the variable values, as shown
in Listing 13.23.</P>
<P>
<H4>LISTING 13.23. THE CSerializeView.PopulateView FUNCTION.</H4>
<PRE> 1: void CSerializeView::PopulateView()
 2: {
 3:     // Get a pointer to the current document
 4:     CSerializeDoc* pDoc = GetDocument();
 5:     if (pDoc)
 6:     {
 7:         // Display the current record position in the set
 8:         m_sPosition.Format(&quot;Record %d of %d&quot;, pDoc-&gt;GetCurRecordNbr(),
 9:                 pDoc-&gt;GetTotalRecords());
10:     }
11:     // Do we have a valid record object?
12:     if (m_pCurPerson)
13:     {
14:         // Yes, get all of the record values
15:         m_bEmployed = m_pCurPerson-&gt;GetEmployed();
16:         m_iAge = m_pCurPerson-&gt;GetAge();
17:         m_sName = m_pCurPerson-&gt;GetName();
18:         m_iMaritalStatus = m_pCurPerson-&gt;GetMaritalStatus();
19:     }
20:     // Update the display
21:     UpdateData(FALSE); 
22: }</PRE>
<P>
<H4>Navigating the Record Set</H4>
<P>If you added navigation buttons to your window when you were designing the form,
then adding navigation functionality is a simple matter of adding event-handler functions
for each of these navigation buttons and calling the appropriate navigation function
in the document. Once the document navigates to the appropriate record in the set,
you need to call the function you just created to display the current record. If
the document navigation functions are returning pointers to the new current record
object, you should capture that pointer before calling the function to display the
current record.</P>
<P>To add this functionality to your sample application, add an event handler to
the clicked event for the First button using the Class Wizard. In the function, get
a pointer to the document object. Once you have a valid pointer to the document,
call the document object's GetFirstRecord function, capturing the returned object
pointer in the view CPerson pointer variable. If you receive a valid pointer, call
the PopulateView function to display the record data, as in Listing 13.24.</P>
<P>
<H4>LISTING 13.24. THE CSerializeView.OnBfirst FUNCTION.</H4>
<PRE> 1: void CSerializeView::OnBfirst()
 2: {
 3:     // TODO: Add your control notification handler code here
 4: 
 5:     // Get a pointer to the current document
 6:     CSerializeDoc * pDoc = GetDocument();
 7:     if (pDoc)
 8:     {
 9:         // Get the first record from the document
10:         m_pCurPerson = pDoc-&gt;GetFirstRecord();
11:         if (m_pCurPerson)
12:         {
13:             // Display the current record
14:             PopulateView();
15:  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -