📄 ch10.htm
字号:
<H4>Constructing the CLine Class</H4>
<P>At this time, your CLine class needs to hold only two data elements, the two end
points of the line that it represents. You want to add those two data elements and
add a class constructor that sets both values when creating the class instance. To
do this, follow these steps:</P>
<DL>
<DT></DT>
<DD><B>1. </B>In the Class View tab of the workspace pane, select the CLine class.
<P>
<DT></DT>
<DD><B>2. </B>Right-click the CLine class and choose Add Member Variable from the
pop-up menu.
<P>
<DT></DT>
<DD><B>3. </B>Enter CPoint as the variable type and m_ptFrom as the variable name,
and mark the access as Private. Click OK to add the variable.
<P>
<DT></DT>
<DD><B>4. </B>Repeat steps 2 and 3, naming this variable m_ptTo.
<P>
<DT></DT>
<DD><B>5. </B>Right-click the CLine class and choose Add Member Function from the
pop-up menu.
<P>
<DT></DT>
<DD><B>6. </B>Leave the function type blank, and enter CLine(CPoint ptFrom, CPoint
ptTo) for the function declaration. Click OK to add the function.
<P>
<DT></DT>
<DD><B>7. </B>Edit the new function, adding the code in Listing 10.1.
<P>
</DL>
<H4>LISTING 10.1. THE CLine CONSTRUCTOR.</H4>
<PRE>1: CLine::CLine(CPoint ptFrom, CPoint ptTo)
2: {
3: //Initialize the from and to points
4: m_ptFrom = ptFrom;
5: m_ptTo = ptTo;
6: }
</PRE>
<P>In this object constructor, you are initializing the from and to points with the
points that were passed in to the constructor.</P>
<P>
<H4>Drawing the CLine Class</H4>
<P>To follow correct object-oriented design, your CLine class should be able to draw
itself so that when the view class needs to render the line for the user, it can
just pass a message to the line object, telling it to draw itself. To add this functionality,
follow these steps:</P>
<DL>
<DT></DT>
<DD><B>1. </B>Add a new function to the CLine class by selecting Add Member Function
from the pop-up menu.
<P>
<DT></DT>
<DD><B>2. </B>Specify the function type as void and the function declaration as Draw(CDC
*pDC).
<P>
<DT></DT>
<DD><B>3. </B>Add the code in Listing 10.2 to the Draw function you just added.
<P>
</DL>
<H4>LISTING 10.2. THE CLine Draw FUNCTION.</H4>
<PRE>1: void CLine::Draw(CDC * pDC)
2: {
3: // Draw the line
4: pDC->MoveTo(m_ptFrom);
5: pDC->LineTo(m_ptTo);
6: }
</PRE>
<P>This function is taken almost directly from the application you built a week ago.
It's a simple function that moves to the first point on the device context and then
draws a line to the second point on the device context.</P>
<P>
<H3><A NAME="Heading5"></A>Implementing the Document Functionality</H3>
<P>Now that you have an object to use for representing the drawings made by the user,
you can store these CLine objects on the document object in a simple dynamic array.
To hold this array, you can add a CObArray member variable to the document class.</P>
<P>The CObArray class is an object array class that dynamically sizes itself to accommodate
the number of items placed in it. It can hold any objects that are descended from
the CObject class, and it is limited in size only by the amount of memory in the
system. Other dynamic array classes in MFC include CStringArray, CByteArray, CWordArray,
CDWordArray, and CPtrArray. These classes differ by the type of objects they can
hold.</P>
<P>Add the CObArray to CDay10Doc, using the Add Member Variable Wizard and giving
it a name of m_oaLines.</P>
<P>
<H4>Adding Lines</H4>
<PRE>The first functionality that you need to add to the document class is the ability to add new lines. This should be a simple process of getting the from and to points, creating a new line object, and then adding it to the object array. To
implement this function, add a new member function to the CDay10Doc class, specifying the type as CLine* and the declaration as AddLine(CPoint ptFrom, CPoint ptTo) with public access. Edit the function, adding the code in Listing 10.3.
</PRE>
<H4>LISTING 10.3. THE CDay10Doc AddLine FUNCTION.</H4>
<PRE> 1: CLine * CDay10Doc::AddLine(CPoint ptFrom, CPoint ptTo)
2: {
3: // Create a new CLine object
4: CLine *pLine = new CLine(ptFrom, ptTo);
5: try
6: {
7: // Add the new line to the object array
8: m_oaLines.Add(pLine);
9: // Mark the document as dirty
10: SetModifiedFlag();
11: }
12: // Did we run into a memory exception?
13: catch (CMemoryException* perr)
14: {
15: // Display a message for the user, giving him or her the
16: // bad news
17: AfxMessageBox("Out of memory", MB_ICONSTOP | MB_OK);
18: // Did we create a line object?
19: if (pLine)
20: {
21: // Delete it
22: delete pLine;
23: pLine = NULL;
24: }
25: // Delete the exception object
26: perr->Delete();
27: }
28: return pLine;
29: }
</PRE>
<P>At first, this function is understandable. You create a new CLine instance, passing
the from and to points as constructor arguments. Right after that, however, you have
something interesting, the following flow control construct:</P>
<P>
<PRE> 1: try
2: {
3: .
4: .
5: .
6: }
7: catch (...)
8: {
9: .
10: .
11: .
12: }
</PRE>
<P>What is this? This construct is an example of structured exception handling. Some
code could fail because of a factor beyond your control, such as running out of memory
or disk space, you can place a try section around the code that might have a problem.
The try section should always be followed by one or more catch sections. If a problem
occurs during the code in the try section, the program immediately jumps to the catch
sections. Each catch section specifies what type of exception it handles (in the
case of the AddLine function, it specifically handles memory exceptions only), and
if there is a matching catch section for the type of problem that did occur, that
section of code is executed to give the application a chance to recover from the
problem. If there is no catch section for the type of problem that did occur, your
program jumps to a default exception handler, which will most likely shut down your
application. For more information on structured exception handling, see Appendix
A, "C++ Review."</P>
<P>Within the try section, you add the new CLine instance to the array of line objects.
Next, you call the SetModifiedFlag function, which marks the document as "dirty"
(unsaved) so that if you close the application or open another file without saving
the current drawing first, the application prompts you to save the current drawing
(with the familiar Yes, No, Cancel message box).</P>
<P>In the catch section, you inform the user that the system is out of memory and
then clean up by deleting the CLine object and the exception object.</P>
<P>Finally, at the end of the function, you return the CLine object to the calling
routine. This enables the view object to let the line object draw itself.</P>
<P>
<H4>Getting the Line Count</H4>
<P>The next item you will add to the document class is a function to return the number
of lines in the document. This functionality is necessary because the view object
needs to loop through the array of lines, asking each line object to draw itself.
The view object will need to be able to determine the total number of lines in the
document and retrieve any specific line from the document.</P>
<P>Returning the number of lines in the document is a simple matter of returning
the number of lines in the object array, so you can just return the return value
from the GetSize method of the CObArray class. To implement this function, add a
new member function to the CDay10Doc class, specifying the type as int and the declaration
as GetLineCount with public access. Edit the function, adding the code in Listing
10.4.</P>
<P>
<H4>LISTING 10.4. THE CDay10Doc GetLineCount FUNCTION.</H4>
<PRE>1: int CDay10Doc::GetLineCount()
2: {
3: // Return the array count
4: return m_oaLines.GetSize();
5: }
</PRE>
<H4>Retrieving a Specific Line</H4>
<P>Finally, you need to add a function to return a specific line from the document.
This is a simple matter of returning the object at the specified position in the
object array. To implement this function, add a new member function to the CDay10Doc
class, specifying the type as CLine* and the declaration as GetLine(int nIndex) with
public access. Edit the function, adding the code in Listing 10.5.</P>
<P>
<H4>LISTING 10.5. THE CDay10Doc GetLine FUNCTION.</H4>
<PRE>1: CLine * CDay10Doc::GetLine(int nIndex)
2: {
3: // Return a pointer to the line object
4: // at the specified point in the object array
5: return (CLine*)m_oaLines[nIndex];
6: }</PRE>
<BLOCKQUOTE>
<P>
<HR>
<STRONG>NOTE:</STRONG> Notice that the object being returned had to be cast as a
pointer to a CLine object. Because the CObArray class is an array of CObjects, every
element that is returned by the array is a CObject instance, not a CLine object instance.
<HR>
</BLOCKQUOTE>
<H3><A NAME="Heading6"></A>Showing the User</H3>
<P>Now that you have built the capability into the document class to hold the drawing,
you need to add the functionality to the view object to read the user's drawing input
and to draw the image. The mouse events to capture the user input are almost identical
to those you created a week ago. The second part of the functionality that you need
to implement is drawing the image. You will make an addition to a function that already
exists in the view object class.</P>
<P>Before adding these functions, you need to add a member variable to the CDay10View
class to maintain the previous mouse point, just as you did a week ago. Add a member
variable to the CDay10View class through the workspace pane, specifying the type
as CPoint, the name as m_ptPrevPos, and the access as private.</P>
<P>
<H4>Adding the Mouse Events</H4>
<P>To add the mouse events to capture the user's drawing efforts, open the Class
Wizard and add functions to the CDay10View class for the WM_LBUTTONDOWN, WM_LBUTTONUP,
and WM_MOUSEMOVE event messages. Edit the functions as in Listing 10.6.</P>
<P>
<H4>LISTING 10.6. THE CDay10View MOUSE FUNCTIONS.</H4>
<PRE> 1: void CDay10View::OnLButtonDown(UINT nFlags, CPoint point)
2: {
3: // TODO: Add your message handler code here and/or call default
4:
5: ///////////////////////
6: // MY CODE STARTS HERE
7: ///////////////////////
8:
9: // Capture the mouse, so no other application can
10: // grab it if the mouse leaves the window area
11: SetCapture();
12: // Save the point
13: m_ptPrevPos = point;
14:
15: ///////////////////////
16: // MY CODE ENDS HERE
17: ///////////////////////
18:
19: CView::OnLButtonDown(nFlags, point);
20: }
21:
22: void CDay10View::OnLButtonUp(UINT nFlags, CPoint point)
23: {
24: // TODO: Add your message handler code here and/or call default
25:
26: ///////////////////////
27: // MY CODE STARTS HERE
28: ///////////////////////
29:
30: // Have we captured the mouse?
31: if (GetCapture() == this)
32: // If so, release it so other applications can
33: // have it
34: ReleaseCapture();
35:
36: ///////////////////////
37: // MY CODE ENDS HERE
38: ///////////////////////
39:
40: CView::OnLButtonUp(nFlags, point);
41: }
42:
43: void CDay10View::OnMouseMove(UINT nFlags, CPoint point)
44: {
45: // TODO: Add your message handler code here and/or call default
46:
47: ///////////////////////
48: // MY CODE STARTS HERE
49: ///////////////////////
50:
51: // Check to see if the left mouse button is down
52: if ((nFlags & MK_LBUTTON) == MK_LBUTTON)
53: {
54: // Have we captured the mouse?
55: if (GetCapture() == this)
56: {
57: // Get the Device Context
58: CClientDC dc(this);
59:
60: // Add the line to the document
61: CLine *pLine = GetDocument()->AddLine(m_ptPrevPos, point);
62:
63: // Draw the current stretch of line
64: pLine->Draw(&dc);
65:
66: // Save the current point as the previous point
67: m_ptPrevPos = point;
68: }
69: }
70:
71: ///////////////////////
</PRE>
<PRE>72: // MY CODE ENDS HERE
</PRE>
<PRE>73: ///////////////////////
74:
75: CView::OnMouseMove(nFlags, point);
76: }
</PRE>
<P>In the OnLButtonDown function, the first thing you do is call the SetCapture function.
This function "captures" the mouse, preventing any other applications from
receiving any mouse events, even if the mouse leaves the window space of this application.
This enables the user to drag the mouse outside the application window while drawing
and then drag the mouse back into the application window, without stopping the drawing.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -