📄 ch13.htm
字号:
that your application will allow the user to work with a number of records. This
means that you need to include support for holding and navigating these records.
The support for holding the records can be as simple as adding an object array as
a variable to the document class, as you did back on Day 10. This allows you to add
additional record objects as needed. The navigation could be a number of functions
for retrieving the first, last, next, or previous record objects. Finally, you need
informational functionality so that you can determine what record in the set the
user is currently editing.</P>
<P>To hold and support this functionality, the document class will probably need
two variables, the object array and the current record number in the array. These
two variables will provide the necessary support for holding and navigating the record
set.</P>
<P>For your example, add the two variables for supporting the record set of CPerson
objects as listed in Table 13.4. Specify private access for both variables.</P>
<P>
<H4>TABLE 13.4. DOCUMENT CLASS VARIABLES.</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">
<H4>Name
</TD>
<TD ALIGN="LEFT">
<H4>Type
</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">m_iCurPosition </TD>
<TD ALIGN="LEFT">int </TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">m_oaPeople </TD>
<TD ALIGN="LEFT">CObArray </TD>
</TR>
</TABLE>
</P>
<P>The other thing that you need to do to the document class to provide support for
the record objects is make sure that the document knows about and understands the
record object that it will be holding. You do this by including the custom class
header file before the header file for the document class is included in the document
class source code file. Because the document class needs to trigger actions in the
view class, it's a good idea to also include the header file for the view class in
the document class.</P>
<P>To include these header files in your sample application, open the source-code
file for the document class and add the two #include statements as shown in Listing
13.9.</P>
<P>
<H4>LISTING 13.9. INCLUDING THE CUSTOM AND VIEW CLASSES IN THE DOCUMENT CLASS IMPLEMENTATION.</H4>
<PRE> 1: // SerializeDoc.cpp : implementation of the CSerializeDoc 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 _DEBUG
12: #define new DEBUG_NEW
13: #undef THIS_FILE
14: static char THIS_FILE[] = __FILE__;
15: #endif
16:
17: //////////////////////////////////////////////////////////////////////
18: // CSerializeDoc</PRE>
<P>
<H4>Adding New Records</H4>
<P>Before you can navigate the record set, you need to be able to add new records
to the object array. If you add a private function for adding new records, you can
add new records to the set dynamically as new records are needed. Because new records
should be presenting the user with blank or empty data fields, you don't need to
set any of the record variables when adding a new record to the object array, so
you can use the default constructor.</P>
<P>Following the same logic that you used to add new line records on Day 10, you
should add a new person record to the object array in your document class in today's
sample application. Once you add a new record, you can return a pointer to the new
record so that the view class can directly update the variables in the record object.</P>
<P>Once the new record is added, you will want to set the current record position
marker to the new record in the array. This way, the current record number can easily
be determined by checking the position counter.</P>
<P>If there are any problems in creating the new person record object, let the user
know that the application has run out of available memory and delete the allocated
object, just as you did on Day 10.</P>
<P>To add this functionality to your sample application, add a new member function
to the document class. Specify the type as a pointer to your custom class. If you
named your custom class CPerson, the function type is CPerson*. This function needs
no arguments. Give the function a name that reflects what it does, such as AddNewRecord.
Specify the access for this function as private because it will only be accessed
from other functions within the document class. You can edit the resulting function,
adding the code in Listing 13.10.</P>
<P>
<H4>LISTING 13.10. THE CSerializeDoc.AddNewRecord FUNCTION.</H4>
<PRE> 1: CPerson * CSerializeDoc::AddNewRecord()
2: {
3: // Create a new CPerson object
4: CPerson *pPerson = new CPerson();
5: try
6: {
7: // Add the new person to the object array
8: m_oaPeople.Add(pPerson);
9: // Mark the document as dirty
10: SetModifiedFlag();
11: // Set the new position mark
12: m_iCurPosition = (m_oaPeople.GetSize() - 1);
13: }
14: // Did we run into a memory exception?
15: catch (CMemoryException* perr)
16: {
17: // Display a message for the user, giving them the
18: // bad news
19: AfxMessageBox("Out of memory", MB_ICONSTOP | MB_OK);
20: // Did we create a line object?
21: if (pPerson)
22: {
23: // Delete it
24: delete pPerson;
25: pPerson = NULL;
26: }
27: // Delete the exception object
28: perr->Delete();
29: }
30: return pPerson;
31: }</PRE>
<P>
<H4>Getting the Current Position</H4>
<P>To aid the user in navigating the record set, it's always helpful to provide a
guide about where the user is in the record set. To provide this information, you
need to be able to get the current record number and the total number of records
from the document to display for the user.</P>
<P>The functions to provide this information are both fairly simple. For the total
number of records in the object array, all you need to do is get the size of the
array and return that to the caller.</P>
<P>For your sample application, add a new member function to the document class.
Specify the function type as int, the function name as GetTotalRecords, and the access
as public. Once you add the function, edit it using the code in Listing 13.11.</P>
<P>
<H4>LISTING 13.11. THE CSerializeDoc.GetTotalRecords FUNCTION.</H4>
<PRE>1: int CSerializeDoc::GetTotalRecords()
2: {
3: // Return the array count
4: return m_oaPeople.GetSize();
5: }</PRE>
<P>Getting the current record number is almost just as simple. If you are maintaining
a position counter in the document class, this variable contains the record number
that the user is currently editing. As a result, all you need to do is return the
value of this variable to the calling routine. Because the object array begins with
position 0, you probably need to add 1 to the current position before returning to
display for the user.</P>
<P>To add this function to your sample application, add another new member function
to the document class. Specify the type as int, the function name as GetCurRecordNbr,
and the access as public. Edit the function using the code in Listing 13.12.</P>
<P>
<H4>LISTING 13.12. THE CSerializeDoc.GetCurRecordNbr FUNCTION.</H4>
<PRE>1: int CSerializeDoc::GetCurRecordNbr()
2: {
3: // Return the current position
4: return (m_iCurPosition + 1);
5: }</PRE>
<P>
<H4>Navigating the Record Set</H4>
<P>To make your application really useful, you will need to provide the user with
some way of navigating the record set. A base set of functionality for performing
this navigation is a set of functions in the document class to get pointers to specific
records in the record set. First is a function to get a pointer to the current record.
Next are functions to get pointers to the first and last records in the set. Finally,
you need functions to get the previous record in the set and the next record in the
set. If the user is already editing the last record in the set and attempts to move
to the next record, you can automatically add a new record to the set and provide
the user with this new, blank record.</P>
<P>To add all this functionality, start with the function to return the current record.
This function needs to check the value in the position marker to make sure that the
current record is a valid array position. Once it has made sure that the current
position is valid, the function can return a pointer to the current record in the
array.</P>
<P>To add this function to your sample application, add a new member function to
the document class. Specify the function type as CPerson* (a pointer to the custom
class), the function name as GetCurRecord, and the access as public. Edit the function,
adding the code in Listing 13.13.</P>
<P>
<H4>LISTING 13.13. THE CSerializeDoc.GetCurRecord FUNCTION.</H4>
<PRE> 1: CPerson* CSerializeDoc::GetCurRecord()
2: {
3: // Are we editing a valid record number?
4: if (m_iCurPosition >= 0)
5: // Yes, return the current record
6: return (CPerson*)m_oaPeople[m_iCurPosition];
7: else
8: // No, return NULL
9: return NULL;
10: }</PRE>
<P>The next function you might want to tackle is the function to return the first
record in the array. In this function, you need to first check to make sure that
the array has records. If there are records in the array, set the current position
marker to 0 and return a pointer to the first record in the array.</P>
<P>To add this function to your sample application, add a new member function to
the document class. Specify the function type as CPerson* (a pointer to the custom
class), the function name as GetFirstRecord, and the access as public. Edit the function,
adding the code in Listing 13.14.</P>
<P>
<H4>LISTING 13.14. THE CSerializeDoc.GetFirstRecord FUNCTION.</H4>
<PRE> 1: CPerson* CSerializeDoc::GetFirstRecord()
2: {
3: // Are there any records in the array?
4: if (m_oaPeople.GetSize() > 0)
5: {
6: // Yes, move to position 0
7: m_iCurPosition = 0;
8: // Return the record in position 0
9: return (CPerson*)m_oaPeople[0];
10: }
11: else
12: // No records, return NULL
13: return NULL;
14: }</PRE>
<P>For the function to navigate to the next record in the set, you need to increment
the current position marker and then check to see if you are past the end of the
array. If you are not past the end of the array, you need to return a pointer to
the current record in the array. If you are past the end of the array, you need to
add a new record to the end of the array.</P>
<P>To add this function to your sample application, add a new member function to
the document class. Specify the function type as CPerson* (a pointer to the custom
class), the function name as GetNextRecord, and the access as public. Edit the function,
adding the code in Listing 13.15.</P>
<P>
<H4>LISTING 13.15. THE CSerializeDoc.GetNextRecord FUNCTION.</H4>
<PRE> 1: CPerson * CSerializeDoc::GetNextRecord()
2: {
3: // After incrementing the position marker, are we
4: // past the end of the array?
5: if (++m_iCurPosition < m_oaPeople.GetSize())
6: // No, return the record at the new current position
7: return (CPerson*)m_oaPeople[m_iCurPosition];
8: else
9: // Yes, add a new record
10: return AddNewRecord();
11: }
</PRE>
<P>For the function to navigate to the previous record in the array, you need to
make several checks. First, you need to verify that the array has records. If there
are records in the array, you need to decrement the current position marker. If the
marker is less than zero, you need to set the current position marker to equal zero,
pointing at the first record in the array. Once you've made it through all of this,
you can return a pointer to the current record in the array.</P>
<P>To add this function to your sample application, add a new member function to
the document class. Specify the function type as CPerson* (a pointer to the custom
class), the function name as GetPrevRecord, and the access as public. Edit the function,
adding the code in Listing 13.16.</P>
<P>
<H4>LISTING 13.16. THE CSerializeDoc.GetPrevRecord FUNCTION.</H4>
<PRE> 1: CPerson * CSerializeDoc::GetPrevRecord()
2: {
3: // Are there any records in the array?
4: if (m_oaPeople.GetSize() > 0)
5: {
6: // Once we decrement the current position,
7: // are we below position 0?
8: if (--m_iCurPosition < 0)
9: // If so, set the record to position 0
10: m_iCurPosition = 0;
11: // Return the record at the new current position
12: return (CPerson*)m_oaPeople[m_iCurPosition];
13: }
14: else
15: // No records, return NULL
16: return NULL;
17: }</PRE>
<P>For the function that navigates to the last record in the array, you still need
to check to make sure that there are records in the array. If the array does have
records, you can get the current size of the array and set the current position marker
to one less than the number of records in the array. This is actually the last record
in the array because the first record in the array is record 0. Once you set the
current position marker, you can return a pointer to the last record in the array.</P>
<P>To add this function to your sample application, add a new member function to
the document class. Specify the function type as CPerson* (a pointer to the custom
class), the function name as GetLastRecord, and the access as public. Edit the function,
adding the code in Listing 13.17.</P>
<P>
<H4>LISTING 13.17. THE CSerializeDoc.GetLastRecord FUNCTION.</H4>
<PRE> 1: CPerson * CSerializeDoc::GetLastRecord()
2: {
3: // Are there any records in the array?
4: if (m_oaPeople.GetSize() > 0)
5: {
6: // Move to the last position in the array
7: m_iCurPosition = (m_oaPeople.GetSize() - 1);
8: // Return the record in this position
9: return (CPerson*)m_oaPeople[m_iCurPosition];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -