?? ch09.htm
字號:
set of favorite interfaces.</P><P>The interfaces defined by the Document/View architecture represent guaranteesabout how each of the MFC classes that make up an application behave with regardto each other. For example, the MFC framework always calls the <TT>CDocument::OnNewDocument</TT>function when a new document is created. The MFC framework, and other classes thatmight be part of an MFC-based program, expect the new document to be initializedafter this function has been called.</P><P>Using well-defined interfaces like <TT>CDocument::OnNewDocument</TT> to performspecific tasks enables you to modify only the functions where you must take specialaction; you can let the MFC framework handle most functions and interfaces if youwant the default behavior.</P><P>The Document/View architecture also makes it easy to separate work. For example,data belongs only to the document; a view calls the <TT>GetDocument</TT> functionto collect a document pointer and then uses member functions to collect or updatedata.<H3><FONT COLOR="#000077"><B>Creating a Data Model</B></FONT></H3><P>Each of the interfaces discussed earlier has a specific role. For the remainingexamples in this chapter, you will use the DVTest example created earlier in thishour.</P><P>Return to the DVTest example and add a <TT>CArray</TT> template object to thedocument class as a private data member. Add the source code from Listing 9.11 tothe <TT>CDVTestDoc</TT> class header, found in the <TT>DVTestDoc.h</TT> file. Addthe source code to the attributes section of the class declaration, which beginswith the <TT>// Attributes</TT> comment generated by AppWizard.<H4><FONT COLOR="#000077">TYPE: Listing 9.11. Changes to the CDVTestDoc class declaration.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>// Attributes</TT><TT>public:</TT><TT> CString GetName( int nIndex ) const;</TT><TT> int AddName( const CString& szName );</TT><TT> int GetCount() const;</TT><TT>private:</TT><TT> CArray<CString, CString> m_arNames;</TT></FONT></PRE><P>Because the <TT>CDVTestDoc</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 at the bottom of the <TT>StdAfx.h</TT> file.</P><PRE><FONT COLOR="#0066FF"><TT>#include "afxtempl.h"</TT></FONT></PRE><P>The next step is to implement the functions described in the <TT>CDVTestDoc</TT>class interface. These functions provide access to the data stored in the document.Add the source code in Listing 9.12 to the <TT>DVTestDoc.cpp</TT> file.<H4><FONT COLOR="#000077">TYPE: Listing 9.12. New functions added to the CDVTestDocclass.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>CString CDVTestDoc::GetName( int nIndex ) const</TT><TT>{</TT><TT> ASSERT( nIndex < m_arNames.GetSize() );</TT><TT> return m_arNames[nIndex];</TT><TT>}</TT><TT>int CDVTestDoc::AddName( const CString& szName )</TT><TT>{</TT><TT> return m_arNames.Add( szName );</TT><TT>}</TT><TT>int CDVTestDoc::GetCount() const</TT><TT>{</TT><TT> return m_arNames.GetSize();</TT><TT>}</TT></FONT></PRE><P>Every document class must specify some access functions to add and retrieve data.The three functions in Listing 9.12 are typical access functions in that they donot just expose the <TT>CArray</TT> template. The data could also be stored in anothertype of collection. Storing the data in a <TT>CArray</TT> object is an implementationdetail that should not be of interest to users of the <TT>CDVTestDoc</TT> class.This enables the internal implementation of <TT>CDVTestDoc</TT> to be changed inthe future, if necessary.<H3><FONT COLOR="#000077"><B>Initializing a Document's Contents</B></FONT></H3><P>You create and initialize document objects in two different ways, depending onthe type of application using the document:<UL> <LI>A new MDI document object is created for every new document opened by the program.<BR> <BR> <LI>SDI programs create a single document object that is reinitialized each time a new document is opened.</UL><P>In most cases, the best place to perform any initialization is in the <TT>CDocument::OnNewDocument</TT>member function. This function is provided with some default code inserted by AppWizard.Edit the <TT>OnNewDocument</TT> function so it looks like the code provided in Listing9.13.<H4><FONT COLOR="#000077">TYPE: Listing 9.13. Changes to the CDVTestDoc::OnNewDocumentmember function.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>BOOL CDVTestDoc::OnNewDocument()</TT><TT>{</TT><TT> TRACE( "CDVTest::OnNewDocument" );</TT><TT> if (!CDocument::OnNewDocument())</TT><TT> return FALSE;</TT><TT> m_arNames.RemoveAll();</TT><TT> m_arNames.Add( "Curly" );</TT><TT> m_arNames.Add( "Moe" );</TT><TT> m_arNames.Add( "Shemp" );</TT><TT> return TRUE;</TT><TT>}</TT></FONT></PRE><P>Listing 9.13 clears the contents of the <TT>m_arNames</TT> collection and addsthree new names.<BLOCKQUOTE> <P><HR><B> </B><FONT COLOR="#000077"><B>Time Saver:</B></FONT><B> </B>The <TT>TRACE</TT> macro sends an output message to the compiler's debug window, which displays useful information as the program executes.<BR> In Listing 9.13, the <TT>TRACE</TT> macro will display a line of text when a new document is created. It's a good idea to have your program provide tracing information whenever an interesting event occurs. <HR></BLOCKQUOTE><H3><FONT COLOR="#000077"><B>Getting the Document Pointer</B></FONT></H3><P>Every view is associated with only one document. When a view must communicatewith its associated document, the <TT>GetDocument</TT> function is used. If the viewis created by AppWizard, as <TT>CDVTestView</TT> is, the <TT>GetDocument</TT> functionreturns a pointer to the proper document type. Listing 9.14 is a version of <TT>OnDraw</TT>that uses <TT>GetDocument</TT> to retrieve a pointer to the <TT>CDVTestDoc</TT> class;then it uses the pointer to collect the names contained in the document.<H4><FONT COLOR="#000077">TYPE: Listing 9.14. Using GetDocument to fetch a documentpointer.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>void CDVTestView::OnDraw(CDC* pDC)</TT><TT>{</TT><TT> CDVTestDoc* pDoc = GetDocument();</TT><TT> ASSERT_VALID(pDoc);</TT><TT> // Calculate the space required for a single</TT><TT> // line of text, including the inter-line area.</TT><TT> TEXTMETRIC tm;</TT><TT> pDC->GetTextMetrics( &tm );</TT><TT> int nLineHeight = tm.tmHeight + tm.tmExternalLeading;</TT><TT> CPoint ptText( 0, 0 );</TT><TT> for( int nIndex = 0; nIndex < pDoc->GetCount(); nIndex++ )</TT><TT> {</TT><TT> CString szName = pDoc->GetName( nIndex );</TT><TT> pDC->TextOut( ptText.x, ptText.y, szName );</TT><TT> ptText.y += nLineHeight;</TT><TT> }</TT><TT>}</TT></FONT></PRE><P>There are three main parts to Listing 9.14:<UL> <LI>In the first part, the document pointer is retrieved using <TT>GetDocument</TT>. The pointer value is validated using the <TT>ASSERT_VALID</TT> macro. You should always use this macro after an old-style cast to ensure that the pointer is accurate.<BR> <BR> <LI>In the second part, the size of a line of text is calculated using the <TT>CDC::GetTextMetrics</TT> function. This function fills the <TT>TEXTMETRICS</TT> structure with information about the current font used by the device context. The <TT>tmHeight</TT> member is the maximum height of a character, and the <TT>tmExternalLeading</TT> member is the spacing between character lines. Adding these two values together results in a good spacing value between displayed rows of text.<BR> <BR> <LI>Finally, the third part collects each name in turn from the document, using the functions added earlier to the document class. After each line of text is displayed, the <TT>ptText.x</TT> value is increased by the line spacing value calculated earlier.</UL><P>Compile and run the DVTest project. DVTest displays the names stored in the documentclass, as shown in Figure 9.6.</P><P><A NAME="06"></A><A HREF="06.htm"><B>Figure 9.6.</B> </A><I><BR>DVTest displays three names in its view window.</I></P><P>In Hour 22, "Serialization," you'll learn how to save the document toa file. In Hour 23, "Advanced Views," you'll extend DVTest to include multipleviews; one view will enable you to add names to the document.<H2><FONT COLOR="#000077"><B>Summary</B></FONT></H2><P>In this hour you've learned about pointers and references, as well as the basicDocument/View architecture used in most MFC programs. You learned how to use AppWizardand ClassWizard in SDI and MDI applications, and created a sample program demonstratingthe use of Document/View.<H2><FONT COLOR="#000077"><B>Q&A</B></FONT></H2><DL> <DD><B>Q When I use pointers, sometimes I get an Unhandled Exception error from Windows and my program crashes. The code that causes the problem looks something like this:</B></DL><BLOCKQUOTE> <PRE><FONT COLOR="#0066FF"><TT>int *pBadInt;</TT><TT>*pBadInt = 42; // Error here</TT></FONT></PRE></BLOCKQUOTE><PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE><DL> <DD><B>A</B> There are two problems. First, the pointer isn't initialized. You should always initialize a pointer to either <TT>NULL</TT> or to an area of memory that is dynamically allocated, like this:</DL><BLOCKQUOTE> <PRE><FONT COLOR="#0066FF"><TT>int *pInt = NULL;</TT><TT>int *pInt = new int;</TT></FONT></PRE></BLOCKQUOTE><PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE><DL> <DD>A pointer doesn't automatically set aside any storage area--in the preceding code, <TT>pBadInt</TT> is uninitialized and is pointing to a random area of memory. You must assign the pointer either an address of an existing variable or the address of a block of dynamically allocated memory:</DL><BLOCKQUOTE> <PRE><FONT COLOR="#0066FF"><TT>int n;</TT><TT>int *pInt;</TT><TT>pInt = &n;</TT><TT>*pInt = 42; // Okay</TT><TT>pInt = new int;</TT><TT>*pInt = 42; // Okay</TT><TT>delete pInt;</TT></FONT></PRE></BLOCKQUOTE><PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE><DL> <DD><B>Q I don't get all this Document/View stuff. Wouldn't it be easier to store all the data in the view class?</B><BR> <BR> <B>A</B> It might seem easier at first. However, the MFC framework will provide a great deal of help for free if you follow the Document/View rules. For example, if you try to store your data in your view class, it will be very difficult to provide multiple views for the same document. As you will see in Hour 23, it's fairly straightforward if you follow the Document/View model. Also, as you will see in Hour 22, MFC gives you a great deal of support for loading and storing data stored in your document classes.</DL><H2><FONT COLOR="#000077"><B>Workshop</B></FONT></H2><P>The Workshop is designed to help you anticipate possible questions, review whatyou've learned, and begin thinking ahead to putting your knowledge into practice.The answers to the quiz are in Appendix B, "Quiz Answers."<H3><FONT COLOR="#000077"><B>Quiz</B></FONT></H3><DL> <DD>1. What is the <TT>sizeof</TT> operator used for?<BR> <BR> 2. What are some of the differences between pointers and references?<BR> <BR> 3. What is more efficient to pass as a parameter--a pointer or an object? Why?<BR> <BR> 4. What keyword is used to dynamically allocate memory?<BR> <BR> 5. What keyword is used to release dynamically allocated memory?<BR> <BR> 6. In the Document/View architecture, which classes are responsible for maintaining the user interface?<BR> <BR> 7. What are the four main categories of classes in the Document/View architecture?<BR> <BR> 8. What part of the Document/View architecture is responsible for the application's data?<BR> <BR> 9. What <TT>CView</TT> member function is used to retrieve a pointer to the document associated with the view?<BR> <BR> 10. What <TT>CDocument</TT> member function is used to notify a document's views that their user interface might need to be updated?</DL><H3><FONT COLOR="#000077"><B>Exercises</B></FONT></H3><DL> <DD>1. Use the <TT>TRACE</TT> macro to see when the view requests information from the document. Add a <TT>TRACE</TT> macro to the document's <TT>GetName</TT> function, and experiment with resizing and moving the view to see when the view requests the data.<BR> <BR> 2. Modify the DVTest project so that a line number is displayed for each item in the view.<FONT COLOR="#000077"></FONT></DL><CENTER><P><HR><A HREF="../ch08/ch08.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch10/ch10.htm"><IMGSRC="../button/next.gif" WIDTH="128" HEIGHT="28" ALIGN="BOTTOM" ALT="Next chapter"BORDER="0"></A><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <BR><BR><BR><IMG SRC="../button/corp.gif" WIDTH="284" HEIGHT="45" ALIGN="BOTTOM" ALT="Macmillan Computer Publishing USA"BORDER="0"></P><P>© <A HREF="../copy.htm">Copyright</A>, Macmillan Computer Publishing. Allrights reserved.</CENTER></BODY></HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -