📄 ch23.htm
字号:
<H4><FONT COLOR="#000077">TYPE: Listing 23.1. Constructing a CMultiDocTemplate object
that associates CDVTestDoc and CFormTest.</FONT></H4>
<PRE><FONT COLOR="#0066FF"><TT>CMultiDocTemplate* pDocTemplate;</TT>
<TT>pDocTemplate = new CMultiDocTemplate(</TT>
<TT> IDR_DVTESTTYPE,</TT>
<TT> RUNTIME_CLASS(CDVTestDoc),</TT>
<TT> RUNTIME_CLASS(CChildFrame), // custom MDI child frame</TT>
<TT> RUNTIME_CLASS(CFormTest)); // Change this line</TT>
</FONT></PRE>
<P><TT>AddDocTemplate(pDocTemplate);</TT> Because <TT>CFormTest</TT> is now used,
the class declaration for <TT>CFormTest</TT> must be included into the <TT>DVTest.cpp</TT>
source file. Add the following line after all other <TT>#include</TT> directives
at the top of the <TT>DVTest.cpp</TT> source file:</P>
<PRE><FONT COLOR="#0066FF"><TT>#include "FormTest.h"</TT>
</FONT></PRE>
<H3><FONT COLOR="#000077"><B>Handling Events and Messages in the Form View Class</B></FONT></H3>
<P>A form view must handle a wide variety of messages. Just like any view, it must
support several interfaces as part of the Document/View architecture. However, unlike
other views, a form view must also handle any controls contained by the view. For
example, two events generated by controls must be handled in the <TT>CFormTest</TT>
class:
<UL>
<LI>When the button labeled Apply is pressed, the view should update the document
and prepare for a new entry.<BR>
<BR>
<LI>When the button labeled Close is pressed, the view should be closed.
</UL>
<P>Use ClassWizard to add two message-handling functions for these events, using
the values from Table 23.5.
<H4><FONT COLOR="#000077">Table 23.5. Message-handling events added to the CFormTest
class.</FONT></H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><B>Object ID</B></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><B>Message</B></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><B>Function Name</B></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>IDC_APPLY</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>BN_CLICKED</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>OnApply</TT></TD>
</TR>
<TR ALIGN="LEFT" rowspan="1">
<TD ALIGN="LEFT" VALIGN="TOP"><TT>IDC_CLOSE</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>BN_CLICKED</TT></TD>
<TD ALIGN="LEFT" VALIGN="TOP"><TT>OnClose</TT></TD>
</TR>
</TABLE>
</P>
<P>The code to handle control events is fairly straightforward. Edit the new functions
added to the <TT>CFormTest</TT> class so that they look like the code in Listing
23.2.
<H4><FONT COLOR="#000077">TYPE: Listing 23.2. CFormTest functions used to handle
control messages.</FONT></H4>
<PRE><FONT COLOR="#0066FF"><TT>void CFormTest::OnApply()</TT>
<TT>{</TT>
<TT> CDVTestDoc* pDoc;</TT>
<TT> pDoc = (CDVTestDoc*)GetDocument();</TT>
<TT> ASSERT_VALID( pDoc );</TT>
<TT> CString szName;</TT>
<TT> m_edNames.GetWindowText( szName );</TT>
<TT> m_edNames.SetWindowText( "" );</TT>
<TT> m_edNames.SetFocus();</TT>
<TT> if( szName.GetLength() > 0 )</TT>
<TT> {</TT>
<TT> int nIndex = pDoc->AddName( szName );</TT>
<TT> m_lbNames.InsertString( nIndex, szName );</TT>
<TT> m_lbNames.SetCurSel( nIndex );</TT>
<TT> }</TT>
<TT>}</TT>
<TT>void CFormTest::OnClose()</TT>
<TT>{</TT>
<TT> PostMessage( WM_COMMAND, ID_FILE_CLOSE );</TT>
</FONT></PRE>
<P><TT>}</TT> You must manually add an include statement for the document class.
At the top of the <TT>FormView.cpp</TT> file, add the following line just after all
the other <TT>#include</TT> directives:</P>
<PRE><FONT COLOR="#0066FF"><TT>#include "DVTestDoc.h"</TT>
</FONT></PRE>
<P>The <TT>OnApply</TT> function is split into three main parts:
<UL>
<LI>The document pointer is retrieved and verified, as in the <TT>OnDraw</TT> function
discussed in Hour 9.<BR>
<BR>
<LI>The contents of the edit control are collected and stored in a <TT>CString</TT>
object. After the string is collected, the control is cleared and the input focus
is returned to the edit control. This enables the user to immediately make a new
entry.<BR>
<BR>
<LI>If a string was entered, <TT>szName</TT> will have a length greater than zero.
If so, the name is added to the document and the list box is updated. The <TT>SetCurSel</TT>
function is used to scroll to the new list box item.
</UL>
<P>The <TT>OnClose</TT> member function uses the <TT>PostMessage</TT> function to
send an <TT>ID_FILE_CLOSE</TT> message to the application. This has the same effect
as selecting Close from the File menu.
<H3><FONT COLOR="#000077"><B>Handling <TT>OnInitialUpdate</TT></B></FONT></H3>
<P>When using a form view, update it during <TT>OnInitialUpdate</TT>, as the view
is initially displayed. In Hour 9, <TT>CDVTestView</TT> used <TT>OnDraw</TT> to retrieve
the document's contents and display the items in the view. The <TT>OnInitialUpdate</TT>
function uses similar code, as shown in Listing 23.3. Before editing the code, add
the <TT>OnInitialUpdate</TT> function to the <TT>CFormTest</TT> class using ClassWizard.
<H4><FONT COLOR="#000077">TYPE: Listing 23.3. Using OnInitialUpdate to retrieve data
from the document.</FONT></H4>
<PRE><FONT COLOR="#0066FF"><TT>void CFormTest::OnInitialUpdate()</TT>
<TT>{</TT>
<TT> CFormView::OnInitialUpdate();</TT>
<TT> CDVTestDoc* pDoc = (CDVTestDoc*)GetDocument();</TT>
<TT> ASSERT_VALID(pDoc);</TT>
<TT> for( int nIndex = 0; nIndex < pDoc->GetCount(); nIndex++ )</TT>
<TT> {</TT>
<TT> CString szName = pDoc->GetName( nIndex );</TT>
<TT> m_lbNames.AddString( szName );</TT>
<TT> }</TT>
<TT>}</TT></FONT></PRE>
<BLOCKQUOTE>
<P>
<HR>
<B> </B><FONT COLOR="#000077"><B>Time Saver:</B></FONT><B> </B>When a dialog box
is displayed, the dialog resource is used to size the dialog box's window. A form
view is not automatically sized this way, which leads to an unexpected display if
you aren't aware of this behavior. However, you can resize the view to the exact
dimensions of the dialog resource by using the <TT>ResizeParentToFit</TT> function.
Add the following two lines of code to the <TT>CFormTest::OnInitialUpdate</TT> member
function:</P>
<PRE><FONT COLOR="#0066FF"><TT>ResizeParentToFit( FALSE );</TT>
<TT>ResizeParentToFit();</TT></FONT></PRE>
</BLOCKQUOTE>
<PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE>
<BLOCKQUOTE>
<P>Nope, it's not a typo; you must call <TT>ResizeParentToFit</TT> twice to make
sure that the size is calculated correctly. The first call allows the view to expand
and the second call shrinks the view to fit the dialog resource.
<HR>
</BLOCKQUOTE>
<H3><FONT COLOR="#000077"><B>Preventing a View Class from Being Resized</B></FONT></H3>
<P>Like all views, you can resize a form view in three ways:
<UL>
<LI>By dragging the view's frame with the mouse<BR>
<BR>
<LI>By pressing the minimize icon<BR>
<BR>
<LI>By pressing the maximize icon
</UL>
<P>Although the minimize button is handy, the other sizing methods are a problem
for form views. Because a form view looks like a dialog box and the control layout
is specified in the dialog resource, preventing the user from resizing is a good
idea.</P>
<P>The form view class doesn't actually have any control over the minimize and maximize
buttons--they belong to the frame, which also controls the capability to change the
size of the view by dragging it with a mouse. The <TT>CChildFrame</TT> class is the
frame used by default in MDI applications, although you can change the frame class
by using a different class name when the document template is created.</P>
<P>To remove the sizable frame and minimize button from the frame class, add two
lines of code to the frame class <TT>PreCreateWindow</TT> member function. The <TT>PreCreateWindow</TT>
function is called just before the window is created. This enables you to change
the style of the window, as shown in Listing 23.4.
<H4><FONT COLOR="#000077">TYPE: Listing 23.4. Using the PreCreateWindow function
to change CChildFrame style attributes.</FONT></H4>
<PRE><FONT COLOR="#0066FF"><TT>BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)</TT>
<TT>{</TT>
<TT> // Mask away the thickframe and maximize button style bits.</TT>
<TT> cs.style &= ~WS_THICKFRAME;</TT>
<TT> cs.style &= ~WS_MAXIMIZEBOX;</TT>
<TT> return CMDIChildWnd::PreCreateWindow(cs);</TT>
</FONT></PRE>
<P><TT>}</TT> The <TT>&=</TT> operator is the C++ bitwise <TT>AND</TT> operator,
which is used to clear or remove a bit that is set in a particular value. The tilde
(<TT>~</TT>) is the C++ inversion operator, used to "flip" the individual
bits of a particular value. These two operators are commonly used together to mask
off attributes that have been set using the bitwise OR operator. In Listing 23.4,
the <TT>WS_THICKFRAME</TT> and <TT>WS_MAXIMIZEBOX</TT> attributes are cleared from
the <TT>cs.style</TT> variable.</P>
<P>Compile and run the DVTest project. Figure 23.4 shows DVTest after a few names
have been added to the list box.</P>
<P><A NAME="04"></A><A HREF="04.htm"><B>Figure 23.4.</B></A> <I><BR>
DVTest after adding a form view to the project.</I>
<H2><FONT COLOR="#000077"><B>Using Multiple Views</B></FONT></H2>
<P>Programs written for Windows sometimes offer multiple views for their data. For
example, many word processors offer print preview and layout views of a document,
in addition to the normal WYSIWYG view that's used most of the time. Providing multiple
views for a single document is a different issue than allowing several different
documents to be open at the same time; each view actually is connected to a single
document, as shown in Figure 23.5.</P>
<P><A NAME="05"></A><A HREF="05.htm"><B>Figure 23.5.</B></A> <I><BR>
Multiple views connected to a single document in an MDI application.</I></P>
<P>The most common reason to use multiple views is because there are different ways
of looking at information contained in a document. For example, a form view often
is used to give detailed information about a particular item in a database; another
view might be used for data entry; still another type of view might be used to provide
a summary of all items in the same database. Offering several views at the same time
provides maximum flexibility for users of the program.</P>
<P>Because each of these views is connected to a single document, there must be some
way to update the views when needed to keep them synchronized. When one of the views
changes the document, all views must immediately be updated.
<BLOCKQUOTE>
<P>
<HR>
<B> </B><FONT COLOR="#000077"><B>Just a Minute:</B></FONT><B> </B>Using multiple
views allows each view to be specialized for a particular purpose. If only a single
view were allowed, that view would have to be extremely flexible to suit the needs
of every user of your program. Creating specialized views for particular purposes
allows each of these views to do a single job for which they are well suited.
<HR>
</BLOCKQUOTE>
<H3><FONT COLOR="#000077"><B>How to Use Multiple Views</B></FONT></H3>
<P>Using multiple views in an MDI application is easy because the Document/View architecture
keeps the document and view classes separate from each other. The document class
is mainly passive; it notifies the framework when views should be updated, but otherwise
relies on the view classes to change or request data stored in the document.</P>
<P>A new view is easily associated with an existing document. After a document class
has been modified to work with multiple views, any number of view classes can be
added to the program without further modifications to the document class. The following
steps are required to modify an MDI program to use multiple views:
<UL>
<LI>Create a new view class in addition to any existing view associated with the
document.<BR>
<BR>
<LI>Create shared resources, if needed, for the new view class.<BR>
<BR>
<LI>Add code to the view classes to properly handle the <TT>OnInitialUpdate</TT>
and <TT>OnUpdate</TT> virtual functions.<BR>
<BR>
<LI>Modify the document class to call <TT>UpdateAllViews</TT> when the data contained
in the document changes.<BR>
<BR>
<LI>Modify the application class so that it stores pointers to document templates
it creates.<BR>
<BR>
<LI>Add code to the main frame class to handle menu selections that select a particular
view.
</UL>
<P>You will learn about each of these steps in the following sections. Because the
Document/View architecture is designed to support multiple views, you can rely on
ClassWizard to write much of the code for you. To reduce the amount of typing needed,
continue to modify the DVTest program from Hour 9.
<H3><FONT COLOR="#000077"><B>Creating a New View</B></FONT></H3>
<P>The first step in adding a new view to an existing document is to define the view
by creating a view class. Any type of view can be added to an existing MDI program.
In this set of examples, the new view displays the names contained in the document
class. The existing form view is used to add names to the <TT>DVTestDoc</TT> document.</P>
<P>The new view class, <TT>CDisplayView</TT>, is derived directly from <TT>CView</TT>.
Because <TT>CDisplayView</TT> only displays information, it must support only two
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -