📄 ch05.htm
字号:
</BLOCKQUOTE>
<P><A HREF="javascript:popUp('05uvc05.gif')"><B>FIG. 5.5</B></A><B> </B><I>The brushes
display shows several patterns inside thick-bordered rectangles.</I></P>
<P><A HREF="javascript:popUp('05uvc06.gif')"><B>FIG. 5.6</B></A><B> </B><I>Without
erasing the background, the Paint1 application's windows appear messy.</I></P>
<H2><I></I></H2>
<H2><A NAME="Heading10"></A>Scrolling Windows</H2>
<P>Those famous screen rectangles known as <I>windows</I> enable you to partition
screen space between various applications and documents. Also, if a document is too
large to completely fit within a window, you can view portions of it and scroll through
it a bit at a time. The Windows operating system and MFC pretty much take care of
the partitioning of screen space. However, if you want to enable users to view portions
of a large document, you must create scrolling windows.</P>
<P>Adding scrollbars to an application from scratch is a complicated task. Luckily
for Visual C++ programmers, MFC handles many of the details involved in scrolling
windows over documents. If you use the document/view architecture and derive your
view window from MFC's CScrollView class, you have scrolling capabilities almost
for free. I say "almost" because you still must handle a few details, which
you learn about in the following sections.</P>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong> If you create your application with AppWizard, you can specify that
you want to use CScrollView as the base class for your view class. To do this, in
the Step 6 of 6 dialog box displayed by AppWizard, select your view window in the
class list and then select CScrollView in the Base Class dialog box, as shown in
Figure 5.7. 
<HR>
</BLOCKQUOTE>
<P><A HREF="javascript:popUp('05uvc07.gif')"><B>FIG. 5.7</B></A><B> </B><I>You can
create a scrolling window from within AppWizard.</I></P>
<H2><I></I></H2>
<H2><A NAME="Heading11"></A>Building the Scroll Application</H2>
<P>In this section, you'll build a sample program called Scroll to experiment with
a scrolling window. When Scroll first runs, it displays five lines of text. Each
time you click the window, five lines of text are added to the display. When you
have more lines of text than fit in the window, a vertical scrollbar appears, enabling
you to scroll to the parts of the documents that you can't see.</P>
<P>As usual, building the application starts with AppWizard. Choose File, New, and
select the Projects tab. Fill in the project name as <B>Scroll</B> and fill in an
appropriate directory for the project files. Make sure that MFC AppWizard (exe) is
selected. Click OK.</P>
<P>Complete the AppWizard steps, selecting the following options:</P>
<P>Step 1: Select Single Document.</P>
<P>Step 2: Use default settings</P>
<P>Step 3: Use default settings.</P>
<P>Step 4: Deselect all check boxes.</P>
<P>Step 5: Use default settings.</P>
<P>Step 6: Select CScrollView from the Base Class drop-down box, as in Figure 5.7.</P>
<P>The New Project Information dialog box should resemble Figure 5.8. Click OK to
create the project.</P>
<P><A HREF="javascript:popUp('05uvc08.gif')"><B>FIG. 5.8</B></A><B> </B><I>Create
a scroll application with AppWizard.</I></P>
<P>This application generates very simple lines of text. You need to keep track only
of the number of lines in the scrolling view at the moment. To do this, add a variable
to the document class by following these steps:</P>
<DL>
<DT></DT>
<DD><B>1. </B>In ClassView, expand the classes and right-click CScrollDoc.
<P>
<DT></DT>
<DD><B>2. </B>Choose Add Member Variable from the shortcut menu.
<P>
<DT></DT>
<DD><B>3. </B>Fill in <B>int</B> as the variable type.
<P>
<DT></DT>
<DD><B>4. </B>Fill in <B>m_NumLines</B> as the variable declaration.
<P>
<DT></DT>
<DD><B>5. </B>Select Public for the Access.
<P>
</DL>
<P>Variables associated with a document are initialized in OnNewDocument(), as discussed
in Chapter 4. In ClassView, expand CScrollDoc and double-click OnNewDocument() to
expand it. Replace the TODO comments with this line of code:</P>
<P>
<PRE>m_NumLines = 5;
</PRE>
<P>To arrange for this variable to be saved with the document and restored when the
document is loaded, you must serialize it as discussed in Chapter 7, "Persistence
and File I/O." Edit CScrollDoc::Serialize() as shown in Listing 5.9.</P>
<P>
<H4>Listing 5.9  CScrollDoc::Serialize()</H4>
<PRE>void CScrollDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_NumLines;
}
else
{
ar >> m_NumLines;
}
</PRE>
<PRE>}
</PRE>
<P>Now all you need to do is use m_NumLines to draw the appropriate number of lines.
Expand the view class, CMyScrollView, in ClassView and double-click OnDraw(). Edit
it until it's the same as Listing 5.10. This is very similar to the ShowFonts() code
from the Paint1 application earlier in this chapter.</P>
<P>
<H4>Listing 5.10  CMyScrollView::OnDraw()</H4>
<PRE>void CMyScrollView::OnDraw(CDC* pDC)
{
CScrollDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// get the number of lines from the document
int numLines = pDoc->m_NumLines;
// Initialize a LOGFONT structure for the fonts.
LOGFONT logFont;
logFont.lfHeight = 24;
logFont.lfWidth = 0;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = 0;
logFont.lfUnderline = 0;
logFont.lfStrikeOut = 0;
logFont.lfCharSet = ANSI_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = PROOF_QUALITY;
logFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
strcpy(logFont.lfFaceName, "Times New Roman");
// Create a new font and select it into the DC.
CFont* font = new CFont();
font->CreateFontIndirect(&logFont);
CFont* oldFont = pDC->SelectObject(font);
// Initialize the position of text in the window.
UINT position = 0;
// Create and display eight example lines.
for (int x=0; x<numLines; ++x)
{
// Create the string to display.
char s[25];
wsprintf(s, "This is line #%d", x+1);
// Print text with the new font.
pDC->TextOut(20, position, s);
position += logFont.lfHeight;
}
// Restore the old font to the DC, and
// delete the font the program created.
pDC->SelectObject(oldFont);
delete font;
</PRE>
<PRE>}
</PRE>
<P>Build and run the Scroll application. You will see a display similar to that in
Figure 5.9. No scrollbars appear because all the lines fit in the window.</P>
<P><A HREF="javascript:popUp('05uvc09.gif')"><B>FIG. 5.9</B></A><B> </B><I>At first,
the scroll application displays five lines of text and no scrollbars.</I></P>
<P>
<H3><A NAME="Heading12"></A>Adding Code to Increase Lines</H3>
<P>To increase the number of lines whenever users click the window, you need to add
a message handler to handle left mouse clicks and then write the code for the handler.
Right-click CMyScrollView in ClassView and choose Add Windows Message Handler. Double-click
WM_LBUTTONDOWN to add a handler and click the Edit Existing button to change the
code. Listing 5.11 shows the completed handler. It simply increases the number of
lines and calls Invalidate() to force a redraw. Like so many message handlers, it
finishes by passing the work on to the base class version of this function.</P>
<P>
<H4>Listing 5.11  CMyScrollView::OnLButtonDown()</H4>
<PRE>void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point)
{
CScrollDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Increase number of lines to display.
pDoc->m_NumLines += 5;
// Redraw the window.
Invalidate();
CScrollView::OnLButtonDown(nFlags, point);
}
</PRE>
<PRE></PRE>
<H3><A NAME="Heading13"></A>Adding Code to Decrease Lines</H3>
<P>So that you can watch scrollbars disappear as well as appear, why not implement
a way for users to decrease the number of lines in the window? If left-clicking increases
the number of lines, it makes sense that right-clicking would decrease it. Add a
handler for WM_RBUTTONDOWN just as you did for WM_LBUTTONDOWN, and edit it until
it's just like Listing 5.12. This function is a little more complicated because it
ensures that the number of lines is never negative.</P>
<P>
<H4>Listing 5.12  CMyScrollView::OnRButtonDown()</H4>
<PRE>void CMyScrollView::OnRButtonDown(UINT nFlags, CPoint point)
{
CScrollDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Decrease number of lines to display.
pDoc->m_NumLines -= 5;
if (pDoc->m_NumLines < 0)
{
pDoc->m_NumLines = 0;
}
// Redraw the window.
Invalidate();
CScrollView::OnRButtonDown(nFlags, point);
</PRE>
<PRE>}
</PRE>
<P>If you build and run Scroll now and click the window, you can increase the number
of lines, but scrollbars don't appear. You need to add some lines to OnDraw() to
make that happen. Before you do, review the way that scrollbars work. You can click
three places on a vertical scrollbar: the thumb (some people call it the elevator),
above the thumb, or below it. Clicking the thumb does nothing, but you can click
and hold to drag it up or down. Clicking above it moves you one page (screenful)
up within the data. Clicking below it moves you one page down. What's more, the size
of the thumb is a visual representation of the size of a page in proportion to the
entire document. Clicking the up arrow at the top of the scrollbar moves you up one
line in the document; clicking the down arrow at the bottom moves you down one line.</P>
<P>What all this means is that the code that draws the scrollbar and handles the
clicks needs to know the size of the entire document, the page size, and the line
size. You don't have to write code to draw scrollbars or to handle clicks on the
scrollbar, but you do have to pass along some information about the size of the document
and the current view. The lines of code you need to add to OnDraw() are in Listing
5.13; add them after the for loop and before the old font is selected back into the
DC.</P>
<P>
<H4>Listing 5.13  Lines to Add to OnDraw()</H4>
<PRE>// Calculate the document size.
CSize docSize(100, numLines*logFont.lfHeight);
// Calculate the page size.
CRect rect;
GetClientRect(&rect);
CSize pageSize(rect.right, rect.bottom);
// Calculate the line size.
CSize lineSize(0, logFont.lfHeight);
// Adjust the scrollers.
</PRE>
<PRE>SetScrollSizes(MM_TEXT, docSize, pageSize, lineSize);
</PRE>
<P>This new code must determine the document, page, and line sizes. The document
size is the width and height of the screen area that could hold the entire document.
This is calculated by using the number of lines in the entire document and the height
of a line. (CSize is an MFC class created especially for storing the widths and heights
of objects.) The page size is simply the size of the client rectangle of this view,
and the line size is the height of the font. By setting the horizontal component
of the line size to 0, you prevent horizontal scrolling.</P>
<P>These three sizes must be passed along to implement scrolling. Simply call SetScrollSizes(),
which takes the mapping mode, document size, page size, and line size. MFC will set
the scrollbars properly for any document and handle user interaction with the scrollbars.</P>
<P>Build and run Scroll again and generate some more lines. You should see a scrollbar
like the one in Figure 5.10. Add even more lines and you will see the thumb shrink
as the document size grows. Finally, resize the application horizontally so that
the text won't all fit. Notice how no horizontal scrollbars appear, because you set
the horizontal line size to 0.</P>
<P><A HREF="javascript:popUp('05uvc10.gif')"><B>FIG. 5.10</B></A><B> </B><I>After
displaying more lines than fit in the window, the vertical scrollbar appears.</I></P>
<H1><I></I></H1>
<CENTER>
<P>
<HR>
<A HREF="../ch04/ch04.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"
ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch06/ch06.htm"><IMG
SRC="../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>
</P>
<P>© <A HREF="../copy.htm">Copyright</A>, Macmillan Computer Publishing. All
rights reserved.
</CENTER>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -