📄 ch19.htm
字号:
tools do not provide them with a facility to get to these properties in any way other
than with code.</P>
<P>Adding a property page to your control is pretty easy. If you select the Resources
view tab in the workspace and expand the dialog folder, you'll see a dialog for your
control's property page already in the folder. Open this dialog, and you'll find
that it's a standard dialog window that you can design using the standard controls
available in the dialog designer. To design the property page for your sample control,
lay out the property page dialog as shown in Figure 19.4, using the property settings
in Table 19.2.</P>
<P><A HREF="javascript:popUp('19fig04.gif')"><B>FIGURE 19.4.</B></A><B> </B><I>The
control property page layout.</I></P>
<P>
<H4>TABLE 19.2. CONTROL PROPERTY SETTINGS.</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Object</TD>
<TD ALIGN="LEFT">Property</TD>
<TD ALIGN="LEFT">Setting</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Static Text</TD>
<TD ALIGN="LEFT">ID</TD>
<TD ALIGN="LEFT">IDC_STATIC</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"></TD>
<TD ALIGN="LEFT">Caption</TD>
<TD ALIGN="LEFT">Maximum Number of Squiggles:</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Edit Box</TD>
<TD ALIGN="LEFT">ID</TD>
<TD ALIGN="LEFT">IDC_ENBRSQUIG</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Static Text</TD>
<TD ALIGN="LEFT">ID</TD>
<TD ALIGN="LEFT">IDC_STATIC</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"></TD>
<TD ALIGN="LEFT">Caption</TD>
<TD ALIGN="LEFT">Maximum Length of Squiggles:</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Edit Box</TD>
<TD ALIGN="LEFT">ID</TD>
<TD ALIGN="LEFT">IDC_ELENSQUIG</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Check Box</TD>
<TD ALIGN="LEFT">ID</TD>
<TD ALIGN="LEFT">IDC_CMAINTDRAW</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"></TD>
<TD ALIGN="LEFT">Caption</TD>
<TD ALIGN="LEFT">Maintain Current Drawing</TD>
</TR>
</TABLE>
</P>
<P>Once you add all the controls and specify their properties, open the Class Wizard
to add variables for these controls. When you add a variable to one of the controls
on the property page dialog, you'll notice an additional combo box on the Add Member
Variable dialog. This new combo box is for the external name of the property that
the variable should be tied to in the control. The drop-down list on this combo box
is a list of all of the standard properties that you might want to tie the property
page control to, but if you are tying it to a custom property, you have to enter
the property name yourself, as shown in Figure 19.5.</P>
<P><A HREF="javascript:popUp('19fig05.gif')"><B>FIGURE 19.5.</B></A><B> </B><I>The
Add Member Variable dialog.</I></P>
<P>Add variables to the controls on the property page for your control, tying them
to the control's properties, as specified in Table 19.3.</P>
<P>
<H4>TABLE 19.3. CONTROL VARIABLES.</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"><I>Object</I></TD>
<TD ALIGN="LEFT"><I>Name</I></TD>
<TD ALIGN="LEFT"><I>Category</I></TD>
<TD ALIGN="LEFT"><I>Type</I></TD>
<TD ALIGN="LEFT"><I>Property</I></TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">IDC_CMAINTDRAW</TD>
<TD ALIGN="LEFT">m_bKeepDrawing</TD>
<TD ALIGN="LEFT">Value</TD>
<TD ALIGN="LEFT">BOOL</TD>
<TD ALIGN="LEFT">KeepCurrentDrawing</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">IDC_ELENSQUIG</TD>
<TD ALIGN="LEFT">m_iLenSquig</TD>
<TD ALIGN="LEFT">Value</TD>
<TD ALIGN="LEFT">int</TD>
<TD ALIGN="LEFT">SquiggleLength</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">IDC_ENBRSQUIG</TD>
<TD ALIGN="LEFT">m_iNbrSquiggles</TD>
<TD ALIGN="LEFT">Value</TD>
<TD ALIGN="LEFT">int</TD>
<TD ALIGN="LEFT">NumberSquiggles</TD>
</TR>
</TABLE>
</P>
<P>Click the OK button to add all these variables to the control property page class.</P>
<P>
<H3><A NAME="Heading10"></A>Adding Basic Control Functionality</H3>
<P>The basic functionality that your control needs is the ability to respond to mouse
clicks by generating a new drawing. To control this behavior, you'll add a second
boolean variable to the control class so that the OnDraw function knows that a mouse
click has been triggered. The easiest place to get the drawing area of the control
is the OnDraw function, so this is where the new drawing needs to be generated. Do
you want the control to generate a new drawing every time the user moves the application
using your control in front of another application? Probably not. You will most likely
want a greater amount of control over the behavior of the control, so it makes sense
to add this second boolean variable. Add a member variable to the control class (CSquiggleCtrl),
specifying the variable type as BOOL, the variable name as m_bGenNewDrawing, and
the variables access as private.</P>
<P>Before you start adding the code to perform all the various tasks, it's important
that you initialize all the member variables in the control class. This consists
of the member variable property, m_keepCurrentDrawing, and the member variable that
you just added, m_bGenNewDrawing. You'll want your control to generate a new drawing
right off the bat, and you probably don't want it to maintain any drawings, unless
the container application explicitly specifies that a drawing is to be maintained.
You'll set these two variables accordingly in the control class constructor, as shown
in Listing 19.8.</P>
<P>
<H4>LISTING 19.8. THE CSquiggleCtrl CONSTRUCTOR.</H4>
<PRE>1: CSquiggleCtrl::CSquiggleCtrl()
2: {
3: InitializeIIDs(&IID_DSquiggle, &IID_DSquiggleEvents);
4:
5: // TODO: Initialize your control's instance data here.
6: // Initialize the variables
7: m_bGenNewDrawing = TRUE;
8: m_keepCurrentDrawing = FALSE;
9: }</PRE>
<P>Next, you'll add the code to generate and display the squiggle drawings. The place
to add this functionality is the OnDraw function in the control class. This function
is called every time that the control needs to draw itself, whether it was hidden
or something triggered the redrawing by calling the Invalidate function on the control.
Once in the OnDraw function, you'll determine whether you need to generate a new
drawing or just draw the existing drawing. Another thing to keep in mind is that
you are responsible for drawing the entire area that the control occupies. This means
that you need to draw the background of the squiggle drawing, or else the squiggles
will be drawn on top of whatever was displayed in that same spot on the screen. (Who
knows? That might be the effect you are looking for.) To add this functionality to
your control, edit the OnDraw function in the control class, adding the code in Listing
19.9.</P>
<P>
<H4>LISTING 19.9. THE CSquiggleCtrl OnDraw FUNCTION.</H4>
<PRE> 1: void CSquiggleCtrl::OnDraw(
2: CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
3: {
4: // TODO: Replace the following code with your own drawing code.
5: //pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)
ÂGetStockObject(WHITE_BRUSH)));
6: //pdc->Ellipse(rcBounds);
7: // Do we need to generate a new drawing?
8: if (m_bGenNewDrawing)
9: {
10: // Set the drawing area for the new drawing
11: m_maDrawing.SetRect(rcBounds);
12: // Clear out the old drawing
13: m_maDrawing.ClearDrawing();
14: // Generate the new drawing
15: m_maDrawing.NewDrawing();
16: // Reset the control flag
17: m_bGenNewDrawing = FALSE;
18: }
19: // Fill in the background
20: pdc->FillRect(rcBounds,
21: CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
22: // Draw the squiggle drawing
23: m_maDrawing.Draw(pdc);
24: }</PRE>
<P>Finally, you'll trigger the control to generate a new drawing whenever the control
is clicked. This requires adding an event handler for the control's OnClick event.
First, however, you'll add a stock method to the control to make sure that it receives
the OnClick event message. To add this stock method, open the Class Wizard and select
the Automation tab. Add a new method to the control class, selecting the DoClick
method from the drop-down list of stock methods that can be added to your control,
as shown in Figure 19.6. Click the OK button to add the method to your control, and
then select the Message Maps tab in the Class Wizard. Select the OnClick event message
from the list of available event messages, and add a function to handle this event
message. Edit the code for the OnClick event handler, adding the code in Listing
19.10.</P>
<P><A HREF="javascript:popUp('19fig06.gif')"><B>FIGURE 19.6.</B></A><B> </B><I>The
Add Method dialog.</I></P>
<P>
<H4>LISTING 19.10. THE CSquiggleCtrl OnClick FUNCTION.</H4>
<PRE> 1: void CSquiggleCtrl::OnClick(USHORT iButton)
2: {
3: // TODO: Add your specialized code here and/or call the base class
4: // Can we generate a new drawing?
5: if (!m_keepCurrentDrawing)
6: {
7: // Set the flag so a new drawing will be generated
8: m_bGenNewDrawing = TRUE;
9: // Invalidate the control to trigger the OnDraw function
10: Invalidate();
11: }
12: COleControl::OnClick(iButton);
13: }</PRE>
<P>In the OnClick function, you check to see whether you could generate a new drawing
or maintain the current drawing. If you could generate a new drawing, you set the
m_bGenNewDrawing flag to TRUE and invalidated the control, which triggers the OnDraw
function.</P>
<P>
<H3><A NAME="Heading11"></A>Adding Methods</H3>
<P>Remember the functionality that you are going to give your control: One of the
functions is loading a squiggle drawing created with the version of the Squiggle
module that you created on Day 16. To add this functionality, you'll add a method
to the control that the container application can call to pass a filename to be loaded.
You've already added one method to your application, a stock method. Adding a custom
method is similar, but you have to provide a little more information to the Add Method
dialog.</P>
<P>In the method to load an existing drawing, you'll create a CFile object for the
filename that was passed as a parameter. The CFile constructor will take the filename
and the flag CFile::modeRead to let it know that you are opening the file for reading
only. Once you create the CFile object, you'll create a CArchive object to read the
file. The CArchive constructor will take the CFile object that you just created and
the CArchive::load flag to tell it that it needs to load the file. At this point,
you can pass the CArchive object to the drawing object's Serialize function and let
it read and load the drawing. Once the drawing is loaded, you need to display the
drawing by invalidating the control. Before you invalidate the control, you probably
want to make sure that the m_bGenNewDrawing flag is set to FALSE so that the drawing
you just loaded won't be overwritten.</P>
<P>To add this functionality to your control, open the Class Wizard and select the
Automation tab. Click the Add Method button to add a custom method. Enter the external
method name in the first combo box; in this case, call it LoadDrawing. The internal
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -