📄 ch07.htm
字号:
<li><P> Double-click the <font color="#008000">CPrint1Doc</font> constructor, and add this line to it:</P>
<pre><font color="#008000">m_numRects = 5;</font></pre>
<P> This line arranges to display five rectangles in a brand-new document.</P>
<li><P> Use ClassWizard to catch mouse clicks (<font color="#008000">WM_LBUTTONDOWN</font> messages) with the <font color="#008000">OnLButtonDown()</font> function of the view class, as shown in Figure 7.7.</P>
</ol>
<A HREF="Ifig07.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig07.gif"><b>Fig. 7.7</b></A>
<P><I>Use ClassWizard to add the </I><I>OnLButtonDown()</I><I> function.</I></P>
<ol start=4>
<li><P> Click the <U>E</U>dit Code button to edit the new <font color="#008000">OnLButtonDown()</font> function. It should resemble Listing 7.1. Now the number of rectangles to be displayed increases each time the user clicks the left mouse button.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing </I><I>7.1—print1View.cpp—</I>CPrint1View::OnLButtonDown()</P>
<p>
<pre><font color="#008000">void CPrint1View::OnLButtonDown(UINT nFlags, CPoint point) </font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CPrint1Doc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> ASSERT_VALID(pDoc);</font></pre>
<pre><font color="#008000"> pDoc->m_numRects++;</font></pre>
<pre><font color="#008000"> Invalidate();</font></pre>
<pre><font color="#008000"> </font></pre>
<pre><font color="#008000"> CView::OnLButtonDown(nFlags, point);</font></pre>
<pre><font color="#008000">}</font></pre>
</p>
<li><P> Use ClassWizard to add the <font color="#008000">OnRButtonDown()</font> function to the view class, as shown in Figure 7.8.</P>
</ol>
<A HREF="Ifig08.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig08.gif"><b>Fig. 7.8</b></A>
<P><I>Use ClassWizard to add the </I><I>OnRButtonDown()</I><I> function.</I></P>
<ol start=6>
<li><P> Click the <U>E</U>dit Code button to edit the new <font color="#008000">OnRButtonDown()</font> function. It should resemble Listing 7.2. Now the number of rectangles to be displayed decreases each time the user clicks the right mouse button.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing </I><I>7.2—print1View.cpp—</I>CPrint1View::OnRButtonDown()</P>
<p>
<pre><font color="#008000">void CPrint1View::OnRButtonDown(UINT nFlags, CPoint point) </font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CPrint1Doc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> ASSERT_VALID(pDoc);</font></pre>
<pre><font color="#008000"> if (pDoc->m_numRects > 0)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> pDoc->m_numRects--;</font></pre>
<pre><font color="#008000"> Invalidate();</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> </font></pre>
<pre><font color="#008000"> CView::OnRButtonDown(nFlags, point);</font></pre>
<pre><font color="#008000">}</font></pre>
</p>
<li><P> Rewrite the view's <font color="#008000">OnDraw()</font> to draw many rectangles. The code is in Listing 7.3. Print1 now draws the selected number of rectangles one below the other, which may cause the document to span multiple pages. It also
displays the number of rectangles that have been added to the document.</P>
</ol>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing </I><I>7.3—print1View.cpp—</I>CPrint1View::OnDraw()</P>
<pre><font color="#008000">void CPrint1View::OnDraw(CDC* pDC)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CPrint1Doc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> ASSERT_VALID(pDoc);</font></pre>
<pre><font color="#008000"> // TODO: add draw code for native data here</font></pre>
<pre><font color="#008000"> pDC->SetMapMode(MM_LOENGLISH);</font></pre>
<pre><font color="#008000"> char s[10];</font></pre>
<pre><font color="#008000"> wsprintf(s, "%d", pDoc->m_numRects);</font></pre>
<pre><font color="#008000"> pDC->TextOut(300, -100, s);</font></pre>
<pre><font color="#008000"> for (int x=0; x<pDoc->m_numRects; ++x)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> pDC->Rectangle(20, -(20+x*200),</font></pre>
<pre><font color="#008000"> 200, -(200+x*200));</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000">}</font></pre>
<P>When you run the application now, you see the window shown in Figure 7.9. The window not only displays the rectangles, but also displays the rectangle count so you can see how many rectangles you've requested. When you choose the <U>F</U>ile, Print
Pre<U>v</U>iew command, you see the print preview window. Click the <U>T</U>wo Page button, and you see the window shown in Figure 7.10. The five rectangles display properly on the first page, with the second page blank.</P>
<A HREF="Ifig09.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig09.gif"><b>Fig. 7.9</b></A>
<P><I>Print1 now displays multiple rectangles.</I></P>
<A HREF="Ifig10.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig10.gif"><b>Fig. 7.10</b></A>
<P><I>Five rectangles are previewed properly: they will print on a single page.</I></P>
<P>Now, go back to the application's main window and click inside the window three times to add three more rectangles. Right-click to remove one. (The rectangle count displayed in the window should be seven.) After you add the additional rectangles,
choose <U>F</U>ile, Print Pre<U>v</U>iew again to see the two-page print preview window. Figure 7.11 shows what you see. The program hasn't a clue as to how to print or preview the additional page. The sixth rectangle runs off the bottom of the first page,
but nothing appears on the second page.</P>
<A HREF="Ifig11.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig11.gif"><b>Fig. 7.11</b></A>
<P><I>Seven rectangles do not yet appear correctly on multiple pages.</I></P>
<P>The first step is to tell MFC how many pages to print (or preview), by calling the <font color="#008000">SetMaxPage()</font> function in the view class's <font color="#008000">OnBeginPrinting()</font> function. AppWizard gave you a skeleton <font
color="#008000">OnBeginPrinting()</font> that does nothing. You are going to modify it so that it resembles Listing 7.4.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing </I><I>7.4—print1View.cpp—</I>CPrint1View::OnBeginPrinting()</P>
<pre><font color="#008000">void CPrint1View::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CPrint1Doc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> ASSERT_VALID(pDoc);</font></pre>
<pre><font color="#008000"> int pageHeight = pDC->GetDeviceCaps(VERTRES);</font></pre>
<pre><font color="#008000"> int logPixelsY = pDC->GetDeviceCaps(LOGPIXELSY);</font></pre>
<pre><font color="#008000"> int rectHeight = (int)(2.2 * logPixelsY);</font></pre>
<pre><font color="#008000"> int numPages = pDoc->m_numRects * rectHeight / pageHeight + 1;</font></pre>
<pre><font color="#008000"> pInfo->SetMaxPage(numPages);</font></pre>
<pre><font color="#008000">}</font></pre>
<p><font color="#008000">OnBeginPrinting()</font> takes two parameters: a pointer to the printer device context and a pointer to a <font color="#008000">CPrintInfo</font> object. Because the default version of <font
color="#008000">OnBeginPrinting()</font> doesn't refer to these two pointers, the parameter names are commented out to avoid compilation warnings, like this:</P>
<pre><font color="#008000">void CPrint1View::OnBeginPrinting(CDC* /*pDC*/ , CPrintInfo* /*pInfo*/)</font></pre>
<P>However, to set the page count, you need to access both the <font color="#008000">CDC</font> and <font color="#008000">CPrintInfo</font> objects, so your first task is to uncomment the function's parameters.</P>
<P>Now, you need to get some information about the device context (which, in this case, is a printer device context). Specifically, you need to know the height of a page (in single dots) and the number of dots per inch. You obtain the height of a page
with a call to <font color="#008000">GetDeviceCaps()</font>. This function gives you information about the capabilities of the device context. You ask for the vertical resolution (the number of printable dots from the top of the page to the bottom) by
passing the constant <font color="#008000">VERTRES</font> as the argument. Passing <font color="#008000">HORZRES</font> gets you the horizontal resolution. There are 29 constants you can pass to <font color="#008000">GetDeviceCaps()</font>, such as <font
color="#008000">NUMFONTS</font> for the number of fonts that are supported and <font color="#008000">DRIVERVERSION</font> for the driver version number. For a complete list, consult the online Visual C++ documentation.</P>
<P>Print1 uses the <font color="#008000">MM_LOENGLISH</font> mapping mode for the device context, which means that the printer output uses units of 1/100 of an inch. To know how many rectangles are going to fit on a page, you have to know the height of a
rectangle in dots so that you can divide "dots per page" by "dots per rectangle" to get "rectangles per page." (You can see now why your application must know all about your document to calculate the page count.) You know that
each rectangle is two inches high with 20/100 of an inch of space between each rectangle. The total distance from the start of one rectangle and the start of the next, then, is 2.2 inches. The call to <font color="#008000">GetDeviceCaps()</font> with an
argument of <font color="#008000">LOGPIXELSY</font> gives the dots per inch of this printer: multiplying by 2.2 gives the dots per rectangle.</P>
<P>You now have all the information to calculate the number of pages needed to fit the requested number of rectangles. You pass that number to <font color="#008000">SetMaxPage()</font>, and the new OnBeginPrinting() is complete.</P>
<P>Once again, build and run the program. Increase the number of rectangles to seven by clicking twice in the main window. The displayed rectangle count should then be seven. Now, choose <U>F</U>ile, Print Pre<U>v</U>iew and take a look at the two-page,
print preview window (see Figure 7.12). Whoops! You've obviously still got a problem somewhere. Although the application is previewing two pages, as it should with seven rectangles, it's printing exactly the same thing on both pages. Obviously, page two
should take up where page one left off, rather than redisplay the same data from the beginning. There's still some work to do.</P>
<A HREF="Ifig12.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig12.gif"><b>Fig. 7.12</b></A>
<P><I>The Print1 application still doesn't display multiple pages correctly.</I></P>
<H3><A ID="I10" NAME="I10"><A ID="I11" NAME="I11"><B>Setting the Origin</B></A></A></H3>
<P>To get the second and subsequent pages to print properly, you have to change where MFC believes the top of the page to be. Currently, MFC just draws the pages exactly as you told it to do in <font color="#008000">CPrint1View::OnDraw()</font>, which
displays all seven rectangles from the top of the page to the bottom. To tell MFC where the new top of the page should be, you first need to override the view class's <font color="#008000">OnPrepareDC()</font> function.</P>
<P>Bring up ClassWizard, and choose the Message Maps tab. Ensure that <font color="#008000">CPrintView</font> is selected in the class <U>n</U>ame box, as shown in Figure 7.13. Click <font color="#008000">CPrintView</font> in the Object <U>I</U>Ds box and
<font color="#008000">OnPrepareDC</font> in the Messages box, then click <U>A</U>dd Function. Click the <U>E</U>dit Code button to edit the newly added function. Add the code shown in Listing 7.5.</P>
<A HREF="Ifig13.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig13.gif"><b>Fig. 7.13</b></A>
<P><I>Use ClassWizard to override the </I><I>OnPrepareDC()</I><I> function.</I></P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing </I><I>7.5—print1View.cpp—</I><B>CPrint1View</B><B>::OnPrepareDC</B>()</P>
<pre><font color="#008000">void CPrint1View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) </font></pre>
<pre><font color="#008000">{ if (pDC->IsPrinting())</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> int pageHeight = pDC->GetDeviceCaps(VERTRES);</font></pre>
<pre><font color="#008000"> int originY = pageHeight * (pInfo->m_nCurPage - 1);</font></pre>
<pre><font color="#008000"> pDC->SetViewportOrg(0, -originY);</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> CView::OnPrepareDC(pDC, pInfo);</font></pre>
<pre><font color="#008000">}</font></pre>
<P>The MFC framework calls <font color="#008000">OnPrepareDC()</font> right before it displays data on-screen or before it prints the data to the printer. (One of the strengths of the device context approach to screen display is that the same code can
often be used for on-screen display and printing.) If the application is about to display data on-screen, you (probably) don't want to change the default processing performed by <font color="#008000">OnPrepareDC()</font>. So, you must check whether the
application is printing data by calling <font color="#008000">IsPrinting()</font>, a member function of the device context class.</P>
<P>If the application is printing, you will determine which part of the data belongs on the current page. You will need the height in dots of a printed page, so you call <font color="#008000">GetDeviceCaps()</font> again.</P>
<P>Next, you must determine a new viewport origin (the position of the coordinates 0,0) for the display. Changing the origin tells MFC where to begin displaying data. For page one, the origin is zero. For page two, it is moved down by the number of dots
on a page. In general, the vertical component is the size of a page times the current page minus one. The page number is a member variable of the <font color="#008000">CPrintInfo</font> class.</P>
<P>After you calculate the new origin, you need only give it to the device context by calling <font color="#008000">SetViewportOrg()</font>. Your changes to <font color="#008000">OnPrepareDC()</font> are complete.</P>
<P>To see your changes in action, build and run your new version of Print1. When the program's main window appears, click twice in the window to add two additional rectangles to the display. (The displayed rectangle count should be seven.) Once again,
choose <U>F</U>ile, Print Pre<U>v</U>iew and look at the two-page print preview window (see Figure 7.14). Now the program previews the document correctly. If you print the document, it will look the same in hard copy as it does in the preview.</P>
<A HREF="Ifig14.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch07/Ifig14.gif"><b>Fig. 7.14</b></A>
<P><I>Print1 finally previews and prints properly.</I></P>
<H3><A ID="I12" NAME="I12"><A ID="I13" NAME="I13"><B>MFC and Printing</B></A></A></H3>
<P>Now you've had a chance to see MFC's printing and print preview support in action. As you added more functionality to the Print1 application, you modified several member functions that were overridden in the view class, including <font
color="#008000">OnDraw()</font>, <font color="#008000">OnBeginPrinting()</font>, and <font color="#008000">OnPrepareDC()</font>. These functions are important to the printing and print preview process. However, there are also other functions that enable
you to add even more printing power to your applications. The functions important to the printing process are listed in Table 7.2 along with their descriptions.</P>
<P><I>Table 7.2—Printing Functions of a View Class</I></P>
<TABLE BORDER>
<TR>
<TD>
<P><B>Function</B></P>
<TD>
<P><b>Description</b></P>
<TR>
<TD>
<pre><font color="#008000">OnBeginPrinting()</font></pre>
<TD>
<P>Override this function to create resources, such as fonts, that you need for printing the document. You also set the maximum page count here.</P>
<TR>
<TD>
<pre><font color="#008000">OnDraw()</font></pre>
<TD>
<P>This function serves triple duty, displaying data in a frame window, a print preview window, or on the printer, depending on the device context sent as the function's parameter.</P>
<TR>
<TD>
<pre><font color="#008000">OnEndPrinting()</font></pre>
<TD>
<P>Override this function to release resources created in <font color="#008000">OnBeginPrinting()</font>.</P>
<TR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -