📄 ch17.htm
字号:
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> //{{AFX_DATA_INIT(CDierollPropPage)</font></pre>
<pre><font color="#008000"> // NOTE: ClassWizard will add member initialization here</font></pre>
<pre><font color="#008000"> // DO NOT EDIT what you see in these blocks of generated code !</font></pre>
<pre><font color="#008000"> //}}AFX_DATA_INIT</font></pre>
<pre><font color="#008000">}</font></pre>
<P>The <font color="#008000">DoDataExchange()</font> function moderates the exchange of data between <font color="#008000">CDierollPropPage</font>, which represents the dialog box that is the property page, and the actual boxes on the user's screen. It,
too, is written by ClassWizard—see Listing 17.5.</P>
<P><I>Listing 17.5—DierollPpg.cpp—CDierollPropPage::DoDataExchange()</I></P>
<pre><font color="#008000">void CDierollPropPage::DoDataExchange(CDataExchange* pDX)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> //{{AFX_DATA_MAP(CDierollPropPage)</font></pre>
<pre><font color="#008000"> // NOTE: ClassWizard will add DDP, DDX, and DDV calls here</font></pre>
<pre><font color="#008000"> // DO NOT EDIT what you see in these blocks of generated code !</font></pre>
<pre><font color="#008000"> //}}AFX_DATA_MAP</font></pre>
<pre><font color="#008000"> DDP_PostProcessing(pDX);</font></pre>
<pre><font color="#008000">}</font></pre>
<P>There is, not surprisingly, a message map for CDierollPropPage, and some registration code (shown in Listing 17.6), that will enable the ActiveX framework to call this code when a user edits the control’s properties.</P>
<P><I>Listing 17.6—DierollPpg.cpp—CDierollPropPage::UpdateRegistry()</I></P>
<pre><font color="#008000">/////////////////////////////////////////////////////////////////////////////</font></pre>
<pre><font color="#008000">// Initialize class factory and guid</font></pre>
<pre><font color="#008000">IMPLEMENT_OLECREATE_EX(CDierollPropPage, "DIEROLL.DierollPropPage.1",</font></pre>
<pre><font color="#008000"> 0x914b21a8, 0x7946, 0x11d0, 0x9b, 0x1, 0, 0x80, 0xc8, 0x1a, 0x39, 0x7c)</font></pre>
<pre><font color="#008000">/////////////////////////////////////////////////////////////////////////////</font></pre>
<pre><font color="#008000">// CDierollPropPage::CDierollPropPageFactory::UpdateRegistry -</font></pre>
<pre><font color="#008000">// Adds or removes system registry entries for CDierollPropPage</font></pre>
<pre><font color="#008000">BOOL CDierollPropPage::CDierollPropPageFactory::UpdateRegistry(BOOL bRegister)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> if (bRegister)</font></pre>
<pre><font color="#008000"> return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(),</font></pre>
<pre><font color="#008000"> m_clsid, IDS_DIEROLL_PPG);</font></pre>
<pre><font color="#008000"> else</font></pre>
<pre><font color="#008000"> return AfxOleUnregisterClass(m_clsid, NULL);</font></pre>
<pre><font color="#008000">}</font></pre>
<P><B>Designing the Control</B></P>
<P>Typically, a control has <I>internal data</I> (properties) and shows them in some way to the user. The user provides input to the control to change its internal data and perhaps the way the control looks. Some controls present data to the user from
other sources, such as databases or remote files. The only internal data that makes sense for the die-roll control, other than some appearance settings that is covered later, is a single integer between 1 and 6 that represents the current number showing in
the die. Eventually, the control will show a dot pattern like a real-world die, but the first implementation of <font color="#008000">OnDraw()</font> will simply display the digit. Another simplification is to hard code the digit to a single value while
coding the basic structure; add the code to roll the die later, while dealing with input from the user.</P>
<H3><B>Displaying the Current Value</B></H3>
<P>Before the value can be displayed, the control must have a value to display. That involves adding a property to the control and then writing the drawing code.</P>
<P><B>Adding a Property</B></P>
<P>ActiveX controls have four types of properties:</P>
<ul>
<li> Stock: These are standard properties supplied to every control, such as font or color. The developer must activate stock properties, but there is little or no coding involved.</P>
<li> Ambient: These are properties of the environment that surrounds the control—of the container into which it has been placed. These cannot be changed, but the control can use them to adjust its own properties. For example, it can set the control's
background color to match the container's background color.</P>
<li> Extended: These are properties that will be handled by the container, typically involving size and placement on the screen.</P>
<li> Custom: These are properties added by the control developer.</P>
</ul>
<P>To add the value to the die-roll control, use ClassWizard to add a custom property called <font color="#008000">Number</font>. Follow these steps:</P>
<ol>
<li><P> Choose <U>V</U>iew, Class<U>W</U>izard, and then click the Automation tab.</P>
<li><P> Make sure that the drop-down list box at the upper-left of the dialog box is set to <font color="#008000">Dieroll</font> (unless you chose a different name when building the control with AppWizard) and that the right-hand box has the class name
<font color="#008000">CDieRollCtrl</font>.</P>
<li><P> Click the Add P<U>r</U>operty button and fill in the dialog box as shown in Figure 17.4.</P>
</ol>
<A HREF="Sfigs04.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch17/Sfigs04.gif"><b>Fig. 17.4</b></A>
<P><I>ClassWizard simplifies the process of adding a custom property to your </I><I>die-rolling control.</I></P>
<ol start=4>
<li><P> Type <B>Number</B> into the External Name combo box and notice how ClassWizard fills in suggested values for the Variable name and Notification function boxes.</P>
<li><P> Select <font color="#008000">short</font> for the type.</P>
<li><P> Click OK to close the Add Property dialog box and OK to close ClassWizard.</P>
</ol>
<P>Before you can write code to display the value of the <font color="#008000">Number</font> property, the property must have a value to display. Control properties are initialized in <font color="#008000">DoPropExchange()</font>. This method actually
implements <I>persistence</I>; that is, it allows the control to be saved as part of a document and read back in when the document is opened. Whenever a new control is created, the properties cannot be read from a file, so they are set to the default
values provided in this method. Controls do not have a <font color="#008000">Serialize()</font> method.</P>
<P>AppWizard generated a skeleton <font color="#008000">DoPropExchange()</font> method whose code is in Listing 17.7.</P>
<P><I>Listing 17.7—DierollCtl.cpp—CDierollCtrl::DoPropExchange()</I></P>
<pre><font color="#008000">void CDierollCtrl::DoPropExchange(CPropExchange* pPX)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));</font></pre>
<pre><font color="#008000"> COleControl::DoPropExchange(pPX);</font></pre>
<pre><font color="#008000"> // TODO: Call PX_ functions for each persistent custom property.</font></pre>
<pre><font color="#008000">}</font></pre>
<P>Notice the use of the version numbers to be sure that a file holding the values was saved by the same version of the control. Take away the <font color="#008000">TODO</font> comment that AppWizard left for you, and add this line:</P>
<pre><font color="#008000"> PX_Short( pPX, "Number", m_number, (short)3 );</font></pre>
<p><font color="#008000">PX_Short()</font> is one of many property-exchange functions that you can call—one for each property type that is supported. The parameters you supply are as follows:</P>
<ul>
<li> The pointer that was passed to <font color="#008000">DoPropExchange()</font></pre>
<li> The external name of the property as you typed it on the ClassWizard Add Property dialog box</P>
<li> The member variable name of the property as you typed it on the ClassWizard Add Property dialog box</P>
<li> The default value for the property (later, you can replace this hard-coded 3 with a random value)</P>
</ul>
<P>The following are the <font color="#008000">PX</font> functions:</P>
<p><font color="#008000">PX_Blob()</font> (for binary large object [BLOB] types)</P>
<p><font color="#008000">PX_Bool()</font></p>
<p><font color="#008000">PX_Color()</font> (<font color="#008000">OLE_COLOR</font>)</P>
<p><font color="#008000">PX_Currency()</font></p>
<p><font color="#008000">PX_DATAPATH</font> (<font color="#008000">CDataPathProperty</font>)</P>
<p><font color="#008000">PX_Double()</font></p>
<p><font color="#008000">PX_Float()</font></p>
<p><font color="#008000">PX_Font()</font></p>
<p><font color="#008000">PX_IUnknown()</font> (for <font color="#008000">LPUNKNOWN</font> types, COM interface pointer)</P>
<p><font color="#008000">PX_Long()</font></p>
<p><font color="#008000">PX_Picture()</font></p>
<p><font color="#008000">PX_Short()</font></p>
<p><font color="#008000">PX_String()</font></p>
<p><font color="#008000">PX_ULong()</font></p>
<p><font color="#008000">PX_UShort()</font></p>
<P>Filling in the property's default value is simple for some properties, but not so simple for others. For example, you set colors with the <font color="#008000">RGB()</font> macro, which takes values for red, green, and blue from 0 to 255 and returns a
<font color="#008000">COLORREF</font>. Say that you had a property with the external name <font color="#008000">EdgeColor</font> and the internal name <font color="#008000">m_edgecolor</font>, and you wanted the property to default to gray. You would code
that like the following:</P>
<pre><font color="#008000">PX_Short( pPX, "EdgeColor", m_edgecolor, RGB(128,128,128) );</font></pre>
<P>Controls with font properties should, by default, set the font to whatever the container is using. To get this font, call the <font color="#008000">COleControl</font> method <font color="#008000">AmbientFont()</font>.</P>
<P><B> Writing the Drawing Code</B></P>
<P>The code to display the number belongs in the <font color="#008000">OnDraw()</font> method of the control class, <font color="#008000">CDierollCtrl</font>. (Controls do not have documents or views.) This function is called automatically whenever
Windows needs to repaint the part of the screen that includes the control. AppWizard generated a skeleton of this method too, shown in Listing 17.8.</P>
<P><I>Listing 17.8—DierollCtl.cpp—CDierollCtrl::OnDraw()</I></P>
<pre><font color="#008000">void CDierollCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, </font></pre>
<pre><font color="#008000"> const CRect& rcInvalid)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> // TODO: Replace the following code with your own drawing code.</font></pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -