⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch17.htm

📁 A very good resource on Visual C++ 6.0 environment. It teaches through step by step approach and fin
💻 HTM
📖 第 1 页 / 共 5 页
字号:
{
     //{{AFX_DATA_INIT(CDierollPropPage)
     // NOTE: ClassWizard will add member initialization here
     //    DO NOT EDIT what you see in these blocks of generated code !
     //}}AFX_DATA_INIT
</PRE>
<PRE>}
</PRE>
<P>The DoDataExchange() function moderates the data exchange between CDierollPropPage,
which represents the dialog box that is the property page, and the actual boxes on
the user's screen. It, too, will have code added by ClassWizard--Listing 17.5 shows
the empty map AppWizard made.</P>
<P>
<H4>Listing 17.5&#160;&#160;DierollPpg.cpp--CDierollPropPage::DoDataExchange()</H4>
<PRE>void CDierollPropPage::DoDataExchange(CDataExchange* pDX)
{
     //{{AFX_DATA_MAP(CDierollPropPage)
     // NOTE: ClassWizard will add DDP, DDX, and DDV calls here
     //    DO NOT EDIT what you see in these blocks of generated code !
     //}}AFX_DATA_MAP
     DDP_PostProcessing(pDX);
</PRE>
<PRE>}
</PRE>
<P>There is, not surprisingly, a message map for CDierollPropPage, and some registration
code (shown in Listing 17.6), that enables the ActiveX framework to call this code
when a user edits the control's properties.</P>
<P>
<H4>Listing 17.6&#160;&#160;DierollPpg.cpp--CDierollPropPageFactory::UpdateRegistry()</H4>
<PRE>/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid
IMPLEMENT_OLECREATE_EX(CDierollPropPage, &quot;DIEROLL.DierollPropPage.1&quot;,
     0x914b21a8, 0x7946, 0x11d0, 0x9b, 0x1, 0, 0x80, 0xc8, 0x1a, 0x39, 0x7c)
/////////////////////////////////////////////////////////////////////////////
// CDierollPropPage::CDierollPropPageFactory::UpdateRegistry -
// Adds or removes system registry entries for CDierollPropPage
BOOL CDierollPropPage::CDierollPropPageFactory::UpdateRegistry(BOOL bRegister)
{
     if (bRegister)
          return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(),
               m_clsid, IDS_DIEROLL_PPG);
     else
          return AfxOleUnregisterClass(m_clsid, NULL);
</PRE>
<PRE>}
</PRE>
<H3><A NAME="Heading4"></A>Designing the Control</H3>
<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 are 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 OnDraw() 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>
<P>
<H2><A NAME="Heading5"></A>Displaying the Current Value</H2>
<P>Before the value can be displayed, the control must have a value. That involves
adding a property to the control and then writing the drawing code.</P>
<P>
<H3><A NAME="Heading6"></A>Adding a Property</H3>
<P>ActiveX controls have four types of properties:</P>

<UL>
	<LI><I>Stock.</I> 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><I>Ambient.</I> These are properties of the environment that surrounds the control--properties
	of the container into which it has been placed. These can't 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><I>Extended.</I> These are properties that the container handles, usually involving
	size and placement onscreen.
	<P>
	<LI><I>Custom.</I> These are properties added by the control developer.
</UL>

<P>To add the value to the die-roll control, use ClassWizard to add a custom property
called Number. Follow these steps:</P>

<DL>
	<DT></DT>
	<DD><B>1. </B>Choose View, ClassWizard, and then click the Automation tab.
	<P>
	<DT></DT>
	<DD><B>2. </B>Make sure that the Project drop-down list box at the upper-left of
	the dialog box is set to Dieroll (unless you chose a different name when building
	the control with AppWizard) and that the Class Name drop-down list box on the right
	has the classname CDieRollCtrl.
	<P>
	<DT></DT>
	<DD><B>3. </B>Click the Add Property button and fill in the dialog box as shown in
	Figure 17.4.
	<P>
	<DT></DT>
	<DD><B>4. </B>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>
	<DT></DT>
	<DD><B>5. </B>Select short for the type.
	<P>
	<DT></DT>
	<DD><B>6. </B>Click OK to close the Add Property dialog box and OK to close ClassWizard.
	<P>
</DL>

<P><A HREF="javascript:popUp('17uvc04.gif')"><B>FIG. 17.4</B></A><B> </B><I>ClassWizard
simplifies the process of adding a custom property to your die-rolling control.</I></P>

<P>Before you can write code to display the value of the Number property, the property
must have a value to display. Control properties are initialized in DoPropExchange().
This method actually implements <I>persistence</I>; that is, it enables 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 can't be read from a file, so they are set
to the default values provided in this method. Controls don't have a Serialize()
method.</P>
<P>AppWizard generated a skeleton DoPropExchange() method; this code is in Listing
17.7.</P>
<P>
<H4>Listing 17.7&#160;&#160;DierollCtl.cpp--CDierollCtrl::DoPropExchange()</H4>
<PRE>void CDierollCtrl::DoPropExchange(CPropExchange* pPX)
{
     ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
     COleControl::DoPropExchange(pPX);
     // TODO: Call PX_ functions for each persistent custom property.
</PRE>
<PRE>}
</PRE>
<P>Notice the use of the version numbers to ensure that a file holding the values
was saved by the same version of the control. Take away the TODO comment that AppWizard
left for you, and add this line:</P>
<P>
<PRE>       PX_Short( pPX, &quot;Number&quot;,  m_number, (short)3 );
</PRE>
<P>PX_Short() 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 DoPropExchange()
	<P>
	<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)
</UL>

<P>The following are the PX functions:</P>
<P>PX_Blob() (for binary large object [BLOB] types)</P>
<P>PX_Bool()</P>
<P>PX_Color() (OLE_COLOR)</P>
<P>PX_Currency()</P>
<P>PX_DATAPATH (CDataPathProperty)</P>
<P>PX_Double()</P>
<P>PX_Float()</P>
<P>PX_Font()</P>
<P>PX_IUnknown() (for LPUNKNOWN types, COM interface pointer)</P>
<P>PX_Long()</P>
<P>PX_Picture()</P>
<P>PX_Short()</P>
<P>PX_String()</P>
<P>PX_ULong()</P>
<P>PX_UShort()</P>
<P>PX_VBXFontConvert()</P>
<P>Filling in the property's default value is simple for some properties but not
for others. For example, you set colors with the RGB() macro, which takes values
for red, green, and blue from 0 to 255 and returns a COLORREF. Say that you had a
property with the external name EdgeColor and the internal name m_edgecolor and you
wanted the property to default to gray. You would code that like the following:</P>
<P>
<PRE>PX_Short( pPX, &quot;EdgeColor&quot;, m_edgecolor, RGB(128,128,128) );
</PRE>
<P>Controls with font properties should, by default, set the font to whatever the
container is using. To get this font, call the COleControl method AmbientFont().</P>
<P>
<H3><A NAME="Heading7"></A>Writing the Drawing Code</H3>
<P>The code to display the number belongs in the OnDraw() method of the control class,
CDierollCtrl. (Controls don't 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>
<H4>Listing 17.8&#160;&#160;DierollCtl.cpp--CDierollCtrl::OnDraw()</H4>
<PRE>void CDierollCtrl::OnDraw(CDC* pdc, const CRect&amp; rcBounds, 
      const CRect&amp; rcInvalid)
{
    // TODO: Replace the following code with your own drawing code.
    pdc-&gt;FillRect(rcBounds, 
             CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
    pdc-&gt;Ellipse(rcBounds);
</PRE>
<PRE>}
</PRE>
<P>As discussed in the &quot;Scrolling Windows&quot; section of Chapter 5, &quot;Drawing
on the Screen,&quot; the framework passes the function a device context to draw in,
a CRect describing the space occupied by your control, and another CRect describing
the space that has been invalidated. The code in Listing 17.8 draws a white rectangle
throughout rcBounds and then draws an ellipse inside that rectangle, using the default
foreground color. You can keep the white rectangle for now, but rather than draw
an ellipse on it, draw a character that corresponds to the value in Number. To do
that, replace the last line in the skeletal OnDraw() with these lines:</P>
<P>
<PRE>    CString val; //character representation of the short value
    val.Format(&quot;%i&quot;,m_number);
    pdc-&gt;ExtTextOut( 0, 0, ETO_OPAQUE, rcBounds, val, NULL );
</PRE>
<P>These code lines convert the short value in m_number (which you associated with
the Number property on the Add Property dialog box) to a CString variable called
val, using the new CString::Format() function (which eliminates one of the last uses
of sprintf() in C++ programming). The ExtTextOut() function draws a piece of text--the
character in val--within the rcBounds rectangle. As the die-roll control is written
now, that number will always be 3.</P>
<P>You can build and test the control right now if you would like to see how little
effort it takes to make a control that does something. Unlike the other ActiveX applications,
a control isn't run as a standalone application in order to register it. Build the
project and fix any typing mistakes. Choose Tools, ActiveX Control Test Container
to bring up the control test container, shown in Figure 17.5.</P>
<P><A HREF="javascript:popUp('17uvc05.gif')"><B>FIG. 17.5</B></A><B> </B><I>The ActiveX
control test container is the ideal place to test your control.</I></P>


<BLOCKQUOTE>
	<P>
<HR>
<strong>NOTE:</strong> If the Tools menu in Developer Studio doesn't include an ActiveX
	Control Test Container item, you can add it to the menu by following these steps:<BR>
	<B></B></P>

	<P><B>1. </B>Choose Tools, Customize.<BR>
	<B></B></P>

	<P><B>2. </B>Click the Tools tab.<BR>
	<B></B></P>

	<P><B>3. </B>Look at the list of tools and make sure that ActiveX Control Test Container
	isn't there.<BR>
	<B></B></P>

	<P><B>4. </B>Go to the bottom of the list and double-click the empty entry.<BR>
	<B></B></P>

	<P><B>5. </B>Type <B>Activ&amp;eX Control Test Container</B> in the entry and press
	Enter.<BR>
	<B></B></P>

	<P><B>6. </B>Click the ... button to the right of the Command box and browse to your
	Visual C++ CD, or to the hard drive on which you installed Visual C++, and to the
	BIN folder beneath the Developer Studio folder. Highlight tstcon32.exe and click
	OK to finish browsing. On many systems the full path will be C:\Program Files\Microsoft
	Visual Studio\Common\Tools\TSTCON32.EXE. Your system may be different.<BR>
	<B></B></P>

	<P><B>7. </B>Click the rightward-pointing arrow beside the Initial Directory box
	and choose Target Directory from the list that appears.<BR>
	<B></B></P>

	<P><B>8. </B>Make sure that the three check boxes across the bottom of the directory
	are not selected.<BR>
	<B></B></P>

	<P><B>9. </B>Click the Close button.<BR>
	If you haven't built a release version and your target is a release version, or if
	you have not built a debug version and your target is a debug version, you will receive
	an error message when you choose Tools, ActiveX Control Test Container. Simply build
	the control and you will be able to choose the menu item.<BR>
	After you have installed the test container under the tools menu, you will not need
	to do so again. By bringing up the test container from within Developer Studio like
	this, you make it simpler to load your die-roll control into the test container.&#160;
<HR>


</BLOCKQUOTE>

<P>Within the test container, choose Edit, Insert New Control and then choose Dieroll
Control from the displayed list. As Figure 17.6 shows, the control appears as a white
rectangle displaying a small number 3. You can move and resize this control within
the container, but that little 3 stays doggedly in the upper-left corner. The next
step is to make that number change when a user clicks the die.</P>
<P>
<H2><A NAME="Heading8"></A>Reacting to a Mouse Click and Rolling the Die</H2>
<P>There are actually two things that you want your control to do when the user clicks
the mouse on the control: to inform the container that the control has been clicked
and to roll the die and display the new internal value.</P>
<P><A HREF="javascript:popUp('17uvc06.gif')"><B>FIG. 17.6</B></A><B> </B><I>By adding
one property and changing two functions, you have transformed the empty shell into
a control that displays a 3.</I></P>
<H3><B></B></H3>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -