📄 apf.htm
字号:
<PRE>void CArrayView::OnLButtonDown(UINT nFlags, CPoint point)
{
ArrayAddDlg dialog(this);
dialog.m_index = 0;
dialog.m_value = 0;
dialog.m_radio = 0;
int result = dialog.DoModal();
if (result == IDOK)
{
if (dialog.m_radio == 0)
array.SetAtGrow(dialog.m_index, dialog.m_value);
else if (dialog.m_radio == 1)
array.InsertAt(dialog.m_index, dialog.m_value, 1);
else
array.Add(dialog.m_value);
Invalidate();
}
CView::OnLButtonDown(nFlags, point);
</PRE>
<PRE>}
</PRE>
<P>This code starts by creating a dialog object and initializing it, as discussed
in Chapter 2, "Dialogs and Controls." If the user exits the dialog box
by clicking the OK button, the OnLButtonDown() function checks the value of the dialog
box's m_radio data member. A value of 0 means that the first radio button (Set) is
selected, 1 means that the second button (Insert) is selected, and 2 means that the
third button (Add) is selected.</P>
<BLOCKQUOTE>
<P>
<HR>
<STRONG>TIP:</STRONG> Chapter 2, "Dialogs and Controls," discusses displaying
dialog boxes and getting values from them.
<HR>
</BLOCKQUOTE>
<P>If the user wants to set an array element, the program calls SetAtGrow(), giving
the array index and the new value as arguments. Unlike the regular SetAt() function,
which you can use only with a currently valid index number, SetAtGrow() will enlarge
the array as necessary to set the specified array element. That's how the extra array
elements were added when you chose to set element 20.</P>
<P>When the user has selected the Insert radio button, the program calls the InsertAt()
function, giving the array index and new value as arguments. This causes MFC to create
a new array element at the index specified, shoving the other array elements forward.
Finally, when the user has selected the Add option, the program calls the Add() function,
which adds a new element to the end of the array. This function's single argument
is the new value to place in the added element. The call to Invalidate() forces the
window to redraw the data display with the new information.</P>
<P>
<H3><A NAME="Heading5"></A>Reading Through the Array</H3>
<P>So that you can see what's happening as you add, change, and delete array elements,
the Array application's OnDraw() function reads through the array, displaying the
values that it finds in each element. Listing F.2 shows the code for this function.</P>
<BLOCKQUOTE>
<P>
<HR>
<STRONG>TIP:</STRONG> Chapter 5, "Drawing on the Screen," shows you how
to write an OnDraw() function and how it is called.
<HR>
</BLOCKQUOTE>
<H4>Listing F.2  CArrayView::OnDraw()</H4>
<PRE>void CArrayView::OnDraw(CDC* pDC)
{
CArrayDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Get the current font's height.
TEXTMETRIC textMetric;
pDC->GetTextMetrics(&textMetric);
int fontHeight = textMetric.tmHeight;
// Get the size of the array.
int count = array.GetSize();
int displayPos = 10;
// Display the array data.
for (int x=0; x<count; ++x)
{
UINT value = array.GetAt(x);
char s[81];
wsprintf(s, "Element %d contains the value %u.", x, value);
pDC->TextOut(10, displayPos, s);
displayPos += fontHeight;
}
</PRE>
<PRE>}
</PRE>
<P>Here, the program first gets the current font's height so that it can properly
space the lines of text that it displays in the window. It then gets the number of
elements in the array by calling the array object's GetSize() function. Finally,
the program uses the element count to control a for loop, which calls the array object's
GetAt() member function to get the value of the currently indexed array element.
The program converts this value to a string for display purposes.</P>
<P>
<H3><A NAME="Heading6"></A>Removing Elements from the Array</H3>
<P>Because it is a right button click in the window that brings up the Remove from
Array dialog box, it is the program's OnRButtonDown() function that handles the element-deletion
duties. Listing F.3 shows this function.</P>
<P>
<H4>Listing F.3  CArrayView::OnRButtonDown()</H4>
<PRE>void CArrayView::OnRButtonDown(UINT nFlags, CPoint point)
{
ArrayRemoveDlg dialog(this);
dialog.m_remove = 0;
dialog.m_removeAll = FALSE;
int result = dialog.DoModal();
if (result == IDOK)
{
if (dialog.m_removeAll)
array.RemoveAll();
else
array.RemoveAt(dialog.m_remove);
Invalidate();
}
CView::OnRButtonDown(nFlags, point);
</PRE>
<PRE>}
</PRE>
<P>In this function, after displaying the dialog box, the program checks the value
of the dialog box's m_removeAll data member. A value of TRUE means that the user
has checked this option and wants to delete all elements from the array. In this
case, the program calls the array object's RemoveAll() member function. Otherwise,
the program calls RemoveAt(), whose single argument specifies the index of the element
to delete. The call to Invalidate() forces the window to redraw the data display
with the new information.</P>
<P>
<H2><A NAME="Heading7"></A>The List Classes</H2>
<P>Lists are like fancy arrays. The MFC list classes use <I>linked lists</I>, which
use pointers to link their elements (called <I>nodes</I>) rather than depend on contiguous
memory locations to order values. Lists are a better data structure to use when you
need to be able to insert and delete items quickly. However, finding items in a list
can be slower than finding items in an array because a list often needs to be traversed
sequentially to follow the pointers from one item to the next.</P>
<P>When using lists, you need to know some new vocabulary. Specifically, you need
to know that the <I>head</I> of a list is the first node in the list and the <I>tail</I>
of the list is the last node in the list (see Figure F.7). Each node knows how to
reach the <I>next</I> node, the one after it in the list. You'll see these terms
used often as you explore MFC's list classes.</P>
<P><A HREF="javascript:popUp('xfuvc07.gif')"><B>FIG. F.7</B></A><B> </B><I>A linked
list has a head and a tail, with the remaining nodes in between.</I></P>
<P>MFC provides three list classes that you can use to create your lists. These classes
are CObList (which represents a list of objects), CPtrList (which represents a list
of pointers), and CStringList (which represents a list of strings). Each of these
classes has similar member functions, and the classes differ in the type of data
that they can hold in their lists. Table F.2 lists and describes the member functions
of the list classes.</P>
<P>
<H4>Table F.2  Member Functions of the List Classes</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"><B>Function</B></TD>
<TD ALIGN="LEFT"><B>Description</B></TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">AddHead()</TD>
<TD ALIGN="LEFT">Adds a node to the head of the list, making the node the new head</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">AddTail()</TD>
<TD ALIGN="LEFT">Adds a node to the tail of the list, making the node the new tail</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Find()</TD>
<TD ALIGN="LEFT">Searches the list sequentially to find the given object pointer and returns a POSITION
value</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">FindIndex()</TD>
<TD ALIGN="LEFT">Scans the list sequentially, stopping at the node indicated by the given index, and
returns a POSITION value for the node</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetAt()</TD>
<TD ALIGN="LEFT">Gets the node at the specified position</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetCount()</TD>
<TD ALIGN="LEFT">Gets the number of nodes in the list</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetHead()</TD>
<TD ALIGN="LEFT">Gets the list's head node</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetHeadPosition()</TD>
<TD ALIGN="LEFT">Gets the head node's position</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetNext()</TD>
<TD ALIGN="LEFT">Gets the next node in the list when iterating over a list</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetPrev()</TD>
<TD ALIGN="LEFT">Gets the previous node in the list when iterating over a list</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetTail()</TD>
<TD ALIGN="LEFT">Gets the list's tail node</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetTailPosition()</TD>
<TD ALIGN="LEFT">Gets the tail node's position</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">InsertAfter()</TD>
<TD ALIGN="LEFT">Inserts a new node after the specified position</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">InsertBefore()</TD>
<TD ALIGN="LEFT">Inserts a new node before the specified position</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">IsEmpty()</TD>
<TD ALIGN="LEFT">Returns TRUE if the list is empty and returns FALSE otherwise</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">RemoveAll()</TD>
<TD ALIGN="LEFT">Removes all nodes from a list</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">RemoveAt()</TD>
<TD ALIGN="LEFT">Removes a single node from a list</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">RemoveHead()</TD>
<TD ALIGN="LEFT">Removes the list's head node</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">RemoveTail()</TD>
<TD ALIGN="LEFT">Removes the list's tail node</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">SetAt()</TD>
<TD ALIGN="LEFT">Sets the node at the specified position</TD>
</TR>
</TABLE>
<BLOCKQUOTE>
<P>
<HR>
<B>List Templates</B></P>
<P>Linked lists are another good use for templates. There is a list and a deque (double-ended
queue) in the Standard Template Library, discussed in Chapter 26, "Exceptions
and Templates." Many developers find the MFC list classes much easier to use
than templates. There are also MFC collection templates, discussed later in this
chapter.
<HR>
</BLOCKQUOTE>
<H3><A NAME="Heading8"></A>Introducing the List Application</H3>
<P>As you've no doubt guessed, now that you know a little about list classes and
their member functions, you're going to get a chance to see lists in action--in the
List application. When you run the application, you see the window shown in Figure
F.8. The window displays the values of the single node with which the list begins.
Each node in the list can hold two different values, both of which are integers.</P>
<P><A HREF="javascript:popUp('xfuvc08.gif')"><B>FIG. F.8</B></A><B> </B><I>The List
application begins with one node in its list.</I></P>
<P>Using the List application, you can experiment with adding and removing nodes
from a list. To add a node, left-click in the application's window. You then see
the dialog box shown in Figure F.9. Enter the two values that you want the new node
to hold and then click OK. When you do, the program adds the new node to the tail
of the list and displays the new list in the window. For example, if you enter the
values <B>55</B> and <B>65</B> in the dialog box, you see the display shown in Figure
F.10.</P>
<P><A HREF="javascript:popUp('xfuvc09.gif')"><B>FIG. F.9</B></A><B> </B><I>A left
click in the window brings up the Add Node dialog box.</I></P>
<P><A HREF="javascript:popUp('xfuvc10.gif')"><B>FIG. F.10</B></A><B> </B><I>Each
node you add to the list can hold two different values.</I></P>
<P>You can also delete nodes from the list. To do this, right-click in the window
to display the Remove Node dialog box (see Figure F.11). Using this dialog box, you
can choose to remove the head or tail node. If you exit the dialog box by clicking
OK, the program deletes the specified node and displays the resulting list in the
window.</P>
<BLOCKQUOTE>
<P>
<HR>
<STRONG>NOTE:</STRONG> If you try to delete nodes from an empty list, the List application
displays a message box, warning you of your error. If the application didn't catch
this possible error, the program could crash when it tries to delete a nonexistent
node.
<HR>
</BLOCKQUOTE>
<P><A HREF="javascript:popUp('xfuvc11.gif')"><B>FIG. F.11</B></A><B> </B><I>Right-click
in the window to delete a node.</I></P>
<P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -