📄 ch17.htm
字号:
<pre><font color="#008000"> Left+5*Xunit, Top + 10*Yunit); //center left</font></pre>
<pre><font color="#008000"> pdc->Ellipse(Left+11*Xunit, Top+6*Yunit,</font></pre>
<pre><font color="#008000"> Left+15*Xunit, Top + 10*Yunit); //center right</font></pre>
<pre><font color="#008000"> pdc->Ellipse(Left+Xunit, Top+11*Yunit,</font></pre>
<pre><font color="#008000"> Left+5*Xunit, Top + 15*Yunit); //lower left</font></pre>
<pre><font color="#008000"> pdc->Ellipse(Left+11*Xunit, Top+11*Yunit,</font></pre>
<pre><font color="#008000"> Left+15*Xunit, Top + 15*Yunit); //lower right</font></pre>
<pre><font color="#008000"> break;</font></pre>
<pre><font color="#008000"> }</font></pre>
<P>Build the OCX again and try it out in the test container. You should see something similar to Figure 17.11, which actually looks like a die!</P>
<A HREF="Sfigs11.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch17/Sfigs11.gif"><b>Fig. 17.11</b></A>
<P><I>Your rolling-die control now looks like a die.</I></P>
<P>If you're sharp-eyed or if you stretch the die very small, you might notice that the pattern of dots is just slightly off-center. That's because the control’s height and width are not always an exact multiple of 16. For example, if <font
color="#008000">Width()</font> returned 31, <font color="#008000">Xunit</font> would be 1, and all the dots would be arranged between positions 0 and 16—leaving a wide blank band at the far right of the control. Luckily, the width is typically far
more than 31 pixels, and so the asymmetry is less noticeable. </P>
<P>To fix this, center the dots in the control. Find the lines that calculate <font color="#008000">Xunit</font> and <font color="#008000">Yunit</font>, then add the new lines from the code fragment in Listing 17.12. </P>
<P><I>Listing 17.12—DierollCtl.cpp—Adjusting Xunit and Yunit</I></P>
<pre><font color="#008000"> //dots are 4 units wide and high, one unit from the edge</font></pre>
<pre><font color="#008000"> int Xunit = rcBounds.Width()/16;</font></pre>
<pre><font color="#008000"> int Yunit = rcBounds.Height()/16;</font></pre>
<pre><font color="#008000"> int Xleft = rcBounds.Width()%16;</font></pre>
<pre><font color="#008000"> int Yleft = rcBounds.Height()%16;</font></pre>
<pre><font color="#008000"> // adjust top left by amount left over</font></pre>
<pre><font color="#008000"> int Top = rcBounds.top + Yleft/2;</font></pre>
<pre><font color="#008000"> int Left = rcBounds.left + Xleft/2; </font></pre>
<p><font color="#008000">Xleft</font> and <font color="#008000">Yleft</font> are the "leftovers" in the X and Y direction. By moving <U>Top</U> and <font color="#008000">Left</font> over by half the leftover, we centre the dots in the control
without having to change any other code.</P>
<H3><B>Property Sheets</B></H3>
<P>ActiveX controls have property sheets that enable the user to set properties without any change to the container application. (Property sheets and pages are discussed in <A HREF="index12.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index12.htm" target="text">Chapter 12</A>, “Property Pages and
Sheets and Wizards.”) You set these up as dialog boxes, taking advantage of prewritten pages for font, color, and other common properties. For this control, the obvious properties to add are the following:</P>
<ul>
<li> A flag to indicate whether the value should be displayed as a digit or a dot pattern</P>
<li> Foreground color</P>
<li> Background color</P>
</ul>
<blockquote><p><img src="note.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/note.gif">
<P>It's easy to get confused about what, exactly, a property page is: Is each one of the tabs on a dialog box a separate page, or is the whole collection of tabs a page? Each tab is called a <I>page</I> and the collection of tabs is called a <I>sheet.</I>
You set up each page as a dialog box and use ClassWizard to connect the values on that dialog box to member variables.</P>
<p><img src="bottom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/bottom.gif"></blockquote>
<P><B>Digits versus Dots</B></P>
<P>It's a simple enough matter to allow the user to choose whether to display the current value as a digit or a dot pattern. Simply add a property that indicates this preference and then use the property in <font color="#008000">OnDraw()</font>. The user
can set the property using the property page.</P>
<P>First, add the property using ClassWizard. Here's how: Bring up ClassWizard and select the Automation tab. Make sure that the <font color="#008000">CDierollCtrl</font> class is selected and then click Add P<U>r</U>operty. On the Add Property dialog
box, provide the external name <font color="#008000">Dots</font> and the internal name <font color="#008000">m_dots</font>. The type should be <font color="#008000">BOOL</font>, because <font color="#008000">Dots</font> can be either <font
color="#008000">TRUE</font> or <font color="#008000">FALSE</font>. Implement this new property as a member variable (direct-access) property. Click OK to complete the Add Property dialog box and click OK to close ClassWizard. The member variable is added
to the class, the dispatch map is updated, and a stub is added for the notification function, <font color="#008000">OnDotsChanged()</font>.</P>
<P>To initialize <font color="#008000">Dots</font> and arrange for it to be saved with a document, add the following line to <font color="#008000">DoPropExchange()</font> after the call to <font color="#008000">PX_Short()</font>:</P>
<pre><font color="#008000"> PX_Bool( pPX, "Dots", m_dots, TRUE);</font></pre>
<P>Initializing the <font color="#008000">Dots</font> property to <font color="#008000">TRUE</font> ensures that the default behavior of the control is to display the dot pattern.</P>
<P>In <font color="#008000">OnDraw()</font>, uncomment those lines that displayed the digit. Wrap an <font color="#008000">if</font> around them so the digit is displayed if <font color="#008000">m_dots</font> is <font color="#008000">FALSE</font>, and
dots are displayed if it is <font color="#008000">TRUE</font>. The code looks like Listing 17.13.</P>
<P><I>Listing 17.13—DierollCtl.cpp—CDierollCtrl::OnDraw()</I></P>
<pre><font color="#008000">void CDierollCtrl::OnDraw(</font></pre>
<pre><font color="#008000"> CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> pdc->FillRect(rcBounds, </font></pre>
<pre><font color="#008000"> CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));</font></pre>
<pre><font color="#008000"> if (!m_dots)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> CString val; //character representation of the short value</font></pre>
<pre><font color="#008000"> val.Format("%i",m_number);</font></pre>
<pre><font color="#008000"> pdc->ExtTextOut( 0, 0, ETO_OPAQUE, rcBounds, val, NULL ); </font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> else</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> //dots are 4 units wide and high, one unit from the edge</font></pre>
<pre><font color="#008000"> int Xunit = rcBounds.Width()/16;</font></pre>
<pre><font color="#008000"> int Yunit = rcBounds.Height()/16;</font></pre>
<pre><font color="#008000"> int Xleft = rcBounds.Width()%16;</font></pre>
<pre><font color="#008000"> int Yleft = rcBounds.Height()%16;</font></pre>
<pre><font color="#008000"> // adjust top left by amount left over</font></pre>
<pre><font color="#008000"> int Top = rcBounds.top + Yleft/2;</font></pre>
<pre><font color="#008000"> int Left = rcBounds.left + Xleft/2; </font></pre>
<pre><font color="#008000"> CBrush Black;</font></pre>
<pre><font color="#008000"> Black.CreateSolidBrush(RGB(0x00,0x00,0x00)); //solid black brush</font></pre>
<pre><font color="#008000"> CBrush* savebrush = pdc->SelectObject(&Black);</font></pre>
<pre><font color="#008000"> </font></pre>
<pre><font color="#008000"> switch(m_number)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> case 1:</font></pre>
<pre><font color="#008000"> ...</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> pdc->SelectObject(savebrush);</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000">}</font></pre>
<P>To give the user a way to set <font color="#008000">Dots</font>, you build a property page by following these steps:</P>
<ol>
<li><P> Click the ResourceView tab in the Project Workspace window and then click the + next to Dialog.</P>
<li><P> The OCX has two dialog boxes: one for the About box and one for the property page. Double-click <font color="#008000">IDD_PROPPAGE_DIEROLL</font> to open it. The boilerplate property page generated by AppWizard is shown in Figure 17.12.</P>
</ol>
<A HREF="Sfigs12.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch17/Sfigs12.gif"><b>Fig. 17.12</b></A>
<P><I>AppWizard generates an empty property page.</I></P>
<ol start=3>
<li><P> Remove the static control with the <font color="#008000">TODO</font> reminder by highlighting it and pressing Delete.</P>
<li><P> Drag a check box from the Control Palette onto the dialog box; choose <U>V</U>iew, <U>P</U>roperties; and then pin the Property dialog box in place.</P>
<li><P> Change the caption to <font color="#008000">Display Dot Pattern</font> and change the resource ID to <font color="#008000">IDC_DOTS</font>, as shown in Figure 17.13.</P>
</ol>
<A HREF="Sfigs13.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch17/Sfigs13.gif"><b>Fig. 17.13</b></A>
<P><I>You build the property page for the die-roll control like any other dialog </I><I>box.</I></P>
<P>When the user brings up the property page and clicks to set or unset the check box, that does not directly affect the value of <font color="#008000">m_dots</font> or the <font color="#008000">Dots</font> property. To connect the dialog box to member
variables, use ClassWizard and follow these steps:</P>
<ol>
<li><P> Bring up Class Wizard while the dialog box is still open and on top and then select the Member Variables tab.</P>
<li><P> Make sure that <font color="#008000">CDierollPropPage</font> is the selected class and that the <font color="#008000">IDC_DOTS</font> resource ID is highlighted, and then click the Add Variable button.</P>
<li><P> Fill in <font color="#008000">m_dots</font> as the name and <font color="#008000">BOOL</font> as the type, and fill in the Optional Property Name combo box with <font color="#008000">Dots</font>, as shown in Figure 17.14.</P>
<li><P> Click OK, and ClassWizard generates code to connect the property page with the member variables in <font color="#008000">CDierollPropPage::DoDataExchange()</font>.</P>
</ol>
<A HREF="Sfigs14.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch17/Sfigs14.gif"><b>Fig. 17.14</b></A>
<P><I>You connect the property page to the properties of the control with </I><I>ClassWizard.</I></P>
<P>The path that data follows can be a little twisty. When the user brings up the property sheet, the value of <font color="#008000">TRUE</font> or <font color="#008000">FALSE</font> is in a temporary variable. Clicking the check box toggles the value of
that temporary variable. When the user clicks OK, that value goes into <font color="#008000">CDierollPropPage::m_dots</font> and also to the Automation property <font color="#008000">Dots</font>. That property has already been connected to <font
color="#008000">CDierollCtrl:: m_dots</font>, so the dispatch map in <font color="#008000">CDierollCtrl</font> will make sure that the other <font color="#008000">m_dots</font> gets changed. Since the <font color="#008000">OnDraw()</font> function uses
<font color="#008000">CDierollCtrl:: m_dots</font>, the appearance of the control changes in response to the change made by the user on the property page. Having the same name for the two member variables makes things more confusing to first-time control
builders, but makes it less confusing in the long run.</P>
<P>This works now. Bui
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -