📄 ch13.htm
字号:
<PRE>1: void CSerializeDoc::Serialize(CArchive& ar)2: {3: // Pass the serialization on to the object array4: 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 closedor a new document is opened. This consists of looping through all objects in theobject array and deleting each and every one. Once all the objects are deleted, theobject array can be reset when you call its RemoveAll function.</P><P>To implement this functionality in your sample application, add an event-handlerfunction to the document class on the DeleteContents event message using the ClassWizard. 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 array10: 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 object17: for (liPos = 0; liPos < liCount; liPos++)18: delete m_oaPeople[liPos];19: // Reset the array20: m_oaPeople.RemoveAll();21: }22: 23: ///////////////////////24: // MY CODE ENDS HERE25: ///////////////////////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. Thisresults in only one record in the object array. Once the new record is added to thearray, you must modify the view to show that a new record exists; otherwise, theview 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 recordset).</P><P>To implement this functionality, you will need to edit the OnNewDocument functionin your document class. This function is already in the document class, so you donot need to add it through the Class Wizard. The first thing that you do in thisfunction is add a new record to the object array. Once the new record is added, youneed to get a pointer to the view object. You use the GetFirstViewPosition functionto get the position of the view object. Using the position returned for the viewobject, 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 createin the view class to tell the view to refresh the current record information beingdisplayed in the form.</P><P>Locate the OnNewDocument function in the document class source code, and add thecode in Listing 13.20. Before you will be able to compile your application, you willneed 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 HERE11: ///////////////////////12: 13: // If unable to add a new record, return FALSE14: if (!AddNewRecord())15: return FALSE;16: 17: // Get a pointer to the view18: POSITION pos = GetFirstViewPosition();19: CSerializeView* pView = (CSerializeView*)GetNextView(pos);20: // Tell the view that it's got a new data set21: if (pView)22: pView->NewDataSet();23: 24: ///////////////////////25: // MY CODE ENDS HERE26: ///////////////////////27: 28: return TRUE;29: }</PRE><P>When opening an existing data set, you don't need to add any new records, butyou still need to let the view object know that it needs to refresh the record beingdisplayed for the user. As a result, you can add the same code to the OnOpenDocumentfunction as you added to the OnNewDocument, only leaving out the first part whereyou added a new record to the object array.</P><P>Add an event-handler function to the document class for the OnOpenDocument eventusing the Class Wizard. Once you add the function, edit it adding the code in Listing13.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 HERE10: ///////////////////////11: 12: // Get a pointer to the view13: POSITION pos = GetFirstViewPosition();14: CSerializeView* pView = (CSerializeView*)GetNextView(pos);15: // Tell the view that it's got a new data set16: if (pView)17: pView->NewDataSet();18: 19: ///////////////////////20: // MY CODE ENDS HERE21: ///////////////////////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 needto add the functionality into the view class to navigate, display, and update therecords. When you first designed your view class, you placed a number of controlson the window for viewing and editing the various data elements in each record. Youalso included controls for navigating the record set. Now you need to attach functionalityto those controls to perform the record navigation and to update the record withany data changes the user makes.</P><P>Because of the amount of direct interaction that the form will have with the recordobject--reading variable values from the record and writing new values to the record--itmakes sense that you want to add a record pointer to the view class as a privatevariable. For your example, add a new member variable to the view class, specifythe type as CPerson*, give it a name such as m_pCurPerson, and specify the accessas private. Next, edit the view source code file and include the header file forthe 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 "stdafx.h" 5: #include "Serialize.h" 6: 7: #include "Person.h" 8: #include "SerializeDoc.h" 9: #include "SerializeView.h"10: 11: #ifdef _DEBUG12: .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 functionalityto display the current record. Because this functionality will be used in severaldifferent places within the view class, it makes the most sense to create a separatefunction to perform this duty. In this function, you get the current values of allthe variables in the record object and place those values in the view class variablesthat are attached to the controls on the window. The other thing that you want todo is get the current record number and the total number of records in the set anddisplay those for the user so that the user knows his or her relative position withinthe record set.</P><P>In your sample application, add a new member function, specify the function typeas void, give the function a name that makes sense, such as PopulateView, and specifythe access as private. In the function, get a pointer to the document object. Onceyou have a valid pointer to the document, format the position text display with thecurrent record number and the total number of records in the set, using the GetCurRecordNbrand 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 thevalues of their respective fields in the record object. Once you set the values ofall of the view class variables, update the window with the variable values, as shownin 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("Record %d of %d", pDoc->GetCurRecordNbr(), 9: pDoc->GetTotalRecords());10: }11: // Do we have a valid record object?12: if (m_pCurPerson)13: {14: // Yes, get all of the record values15: m_bEmployed = m_pCurPerson->GetEmployed();16: m_iAge = m_pCurPerson->GetAge();17: m_sName = m_pCurPerson->GetName();18: m_iMaritalStatus = m_pCurPerson->GetMaritalStatus();19: }20: // Update the display21: 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 functionsfor each of these navigation buttons and calling the appropriate navigation functionin 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. Ifthe document navigation functions are returning pointers to the new current recordobject, you should capture that pointer before calling the function to display thecurrent record.</P><P>To add this functionality to your sample application, add an event handler tothe clicked event for the First button using the Class Wizard. In the function, geta pointer to the document object. Once you have a valid pointer to the document,call the document object's GetFirstRecord function, capturing the returned objectpointer in the view CPerson pointer variable. If you receive a valid pointer, callthe 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 document10: m_pCurPerson = pDoc->GetFirstRecord();11: if (m_pCurPerson)12: {13: // Display the current record14: PopulateView();15: }16: }17: }</PRE><P>For the Last button, perform the same steps as for the First button, but callthe document object's GetLastRecord function, as in Listing 13.25.</P><P><H4>LISTING 13.25. THE CSerializeView.OnBlast FUNCTION.</H4><PRE> 1: void CSerializeView::OnBlast() 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 last record from the document10: m_pCurPerson = pDoc->GetLastRecord();11: if (m_pCurPerson)12: {13: // Display the current record14: PopulateView();15: }16: }17: }</PRE><P>For the Previous and Next buttons, repeat the same steps again, but call the documentobject's GetPrevRecord and GetNextRecord functions. This final step provides yourapplication with all the navigation functionality necessary to move through the recordset. Also, because calling the document's GetNextRecord on the last record in theset automatically adds a new record to the set, you also have the ability to addnew records to the set as needed.</P><P><H4>Saving Edits and Changes</H4><P>When the user enters changes to the data in the controls on the screen, thesechanges somehow need to make their way into the current record in the document. Ifyou are maintaining a pointer in the view
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -