📄 ch20.htm
字号:
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> // draw using the BLOB</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"> // draw without the BLOB</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000">//cleanup after drawing</font></pre>
<P>There are two problems to solve here. First, what will be the test to see if all the properties are loaded? And second, how can you arrange to have OnDraw called again when the properties are ready, if it's already been called, and has already drawn
the control the "BLOBless" way?</P>
<P>The first problem has been solved by adding two new functions to <font color="#008000">COleControl</font>. <font color="#008000">GetReadyState()</font>returns one of these values:</P>
<ul>
<li> <font color="#008000">READYSTATE_UNINITIALIZED</font> means the control is completely unitialized</P>
<li> <font color="#008000">READYSTATE_LOADING</font> means the control properties are loading</P>
<li> <font color="#008000">READYSTATE_LOADED</font> means the properties are all loaded</P>
<li> <font color="#008000">READYSTATE_INTERACTIVE</font> means the control can talk to the user but isn't fully loaded yet</P>
<li> <font color="#008000">READYSTATE_COMPLETE </font>means there is nothing more to wait for</P>
</ul>
<P>The function <font color="#008000">InternalSetReadyState()</font>sets the ready state to one of these values.</P>
<P>The second problem, getting a second call to OnDraw() after the control has already been drawn without the BLOB, has been solved by a new class called <font color="#008000">CDataPathProperty</font>, and its derived class <font
color="#008000">CCachedDataPathProperty</font>. These classes have a member function called <font color="#008000">OnDataAvailable()</font>which catches the Windows message generated when the property has been retrieved from the remote site. The <font
color="#008000">OnDataAvailable()</font>function invalidates the control, forcing a redraw.</P>
<P><A ID="I11" NAME="I11"><B>Changing Dieroll</B></A></P>
<P>Make a copy of the Dieroll folder you created in <A HREF="index17.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index17.htm" target="text">Chapter 17</A>, "Building an ActiveX Control," (or the <A HREF="index17.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index17.htm" target="text">Chapter 17</A> code from the CD) and change it to windowless
activation as described earlier in this chapter. Now you're ready to begin. There is a lot to be done to implement asynchronous properties, but each step is quite straightforward.</P>
<P><A ID="I12" NAME="I12"><B>Add the </B><B><I>CDierollDataPathProperty</I></B><B> class</B></A></P>
<P>Bring up Class Wizard, click the Automation tab, and click the Add Class button. From the drop-down menu that appears under the button, choose New. This brings up the Create New Class dialog box. Name the class <font
color="#008000">CDierollDataPathProperty</font>. Click the drop-down box for Base class and choose <font color="#008000">CCachedDataPathProperty</font>. The dialog box should resemble Figure 20.6. Click OK to create the class and add it to the project.</P>
<A HREF="Vfigs06.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch20/Vfigs06.gif"><b>Fig. 20.6</b></A>
<P><I>Create a new class to handle asynchronous properties.</I></P>
<P>The reason that the new class should inherit from <font color="#008000">CCachedDataProperty</font> is that it will load the property information into a file, and that is an easier way to handle the bitmap. If the control has a property that was
downloaded because it changed often (for example, current weather) then <font color="#008000">CDataPathProperty</font> would be a better choice.</P>
<P><A ID="I13" NAME="I13"><B>Add the Image Property to CDierollCtrl</B></A></P>
<P>With the new <font color="#008000">CDierollDataPathProperty </font>class added to the Dieroll control, add the property to the original <font color="#008000">CDierollCtrl</font> class that you copied, like this: in Class Wizard, on the Automation tab,
make sure that <font color="#008000">CDierollCtrl</font> is selected in the rightmost drop-down box. Click Add Property, and fill out the dialog as shown in Figure 20.7. The external name you choose is the one that will appear in the HTML: <font
color="#008000">Image</font> is simple and doesn't require a lot of typing. The type should be <font color="#008000">OLE_BSTR</font>—that choice won't be in the drop-down box for type until you change the Implementation to Get/Set method.</P>
<A HREF="Vfigs07.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch20/Vfigs07.gif"><b>Fig. 20.7</b></A>
<P><I>The image file is added as a BSTR property.</I></P>
<P>Class Wizard adds the Get and Set functions to your control class, but the TODO comments (see Listing 20.7) are a little cryptic.</P>
<P><I>Listing 20.7—DierollCtl.cpp—Get and Set functions</I></P>
<pre><font color="#008000">BSTR CDierollCtrl::GetImage()</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CString strResult;</font></pre>
<pre><font color="#008000"> // TODO: Add your property handler here</font></pre>
<pre><font color="#008000"> return strResult.AllocSysString();</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000">void CDierollCtrl::SetImage(LPCTSTR lpszNewValue)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> // TODO: Add your property handler here</font></pre>
<pre><font color="#008000"> SetModifiedFlag();</font></pre>
<pre><font color="#008000">}</font></pre>
<P>As with other Get and Set properties, you will have to add a member variable to the control class, and add code to these functions to get or set its value. It is an instance of the new <font color="#008000">CDierollDataPathProperty</font> class.
Right-click on<font color="#008000">CDierollCtrl</font> in Class View and choose Add Member Variable. Figure 20.8 shows how to fill in the dialog box to declare the member variable <font color="#008000">mdpp_image</font>.(The <font
color="#008000">dpp</font> in the name is to remind you that this is a data path property.)</P>
<A HREF="Vfigs08.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch20/Vfigs08.gif"><b>Fig. 20.8</b></A>
<P><I>The image file member variable is an instance of the new class.</I></P>
<P>Now you can finish the Get and Set functions, as shown in Listing 20.8.</P>
<P><I>Listing 20.8—DierollCtl.cpp—Completed Get and Set functions</I></P>
<pre><font color="#008000">BSTR CDierollCtrl::GetImage()</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CString strResult;</font></pre>
<pre><font color="#008000"> strResult = mdpp_image.GetPath();</font></pre>
<pre><font color="#008000"> return strResult.AllocSysString();</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000">void CDierollCtrl::SetImage(LPCTSTR lpszNewValue)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> Load(lpszNewValue, mdpp_image);</font></pre>
<pre><font color="#008000"> SetModifiedFlag();</font></pre>
<pre><font color="#008000">}</font></pre>
<P>At the top of the header file for <font color="#008000">CDierollCtrl</font>, add this include statement:</P>
<pre><font color="#008000">#include "DierollDataPathProperty.h"</font></pre>
<P>Now there are some bits and pieces to deal with because you are changing an existing control rather than turning on asynchronous properties when you first built Dieroll. First, in <font color="#008000">CDierollCtrl::DoPropExchange()</font>, arrange
persistence and initialization for <font color="#008000">mdpp_image</font> by adding this line:</P>
<pre><font color="#008000">PX_DataPath( pPX, _T("Image"), mdpp_image);</font></pre>
<P>Second, add a line to the stub of <font color="#008000">CDierollCtrl::OnResetState()</font>that Class Wizard provided, to reset the data path property when the control is reset. The function is shown in Listing 20.9.</P>
<P><I>Listing 20.9—DierollCtl.cpp—CDierollCtrl::OnResetState()</I></P>
<pre><font color="#008000">/////////////////////////////////////////////////////////////////////////////</font></pre>
<pre><font color="#008000">// CDierollCtrl::OnResetState - Reset control to default state</font></pre>
<pre><font color="#008000">void CDierollCtrl::OnResetState()</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> COleControl::OnResetState(); // Resets defaults found in DoPropExchange</font></pre>
<pre><font color="#008000"> mdpp_image.ResetData();</font></pre>
<pre><font color="#008000">}</font></pre>
<P><A ID="I14" NAME="I14"><B>Add the ReadyStateChange Event and the ReadyState Property</B></A></P>
<P>Use Class Wizard to add the stock event <font color="#008000">ReadyStateChange</font>. In Class Wizard, click the ActiveX Events tab, then the Add Event button. Choose <font color="#008000">ReadyStateChange</font> from the drop-down box and click OK.
Figure 20.9 shows the Add Event dialog box for this event. Events, as discussed in <A HREF="index17.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index17.htm" target="text">Chapter 17</A>, notify the container of the control that something has happened within the control. In this case, what has happened is
that the rest of the control's data has arrived and the control's state of readiness has changed.</P>
<A HREF="Vfigs09.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch20/Vfigs09.gif"><b>Fig. 20.9</b></A>
<P><I>Add a stock event to notify the container of a change in the readiness of the control.</I></P>
<P>Use Class Wizard to add a property to CDierollCtrl for the ready state. In Class Wizard, click the Automation tab, then the Add Property button. Choose <font color="#008000">ReadyState</font> from the dropdown box, and since this is a stock property,
the rest of the dialog box is filled in for you, as shown in Figure 20.10. ClassWizard doesn't add a stub function for <font color="#008000">GetReadyState()</font>because <font color="#008000">CDierollCtrl</font> will inherit this from <font
color="#008000">COleControl</font>.</P>
<A HREF="Vfigs10.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch20/Vfigs10.gif"><b>Fig. 20.10</b></A>
<P><I>Add a stock property to track the readiness of the control.</I></P>
<P>Add code to the constructor to connect the cached property to this control and to initialize the member variable in <font color="#008000">COleControl</font> that is used in <font color="#008000">COleControl::GetReadyState()</font>and set by <font
color="#008000">COleControl::InternalSetReadyState()</font>. Since the control can be used right away, the readiness state should start at <font color="#008000">READYSTATE_INTERACTIVE</font>. Listing 20.10 shows the new constructor:</P>
<P><I>Listing 20.10—DierollCtl.cpp—CDierollCtrl::GetImage()</I></P>
<pre><font color="#008000">CDierollCtrl::CDierollCtrl()</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> InitializeIIDs(&IID_DDieroll, &IID_DDierollEvents);</font></pre>
<pre><font color="#008000"> mdpp_image.SetControl(this);</font></pre>
<pre><font color="#008000"> m_lReadyState = READYSTATE_INTERACTIVE;</font></pre>
<pre><font color="#008000">}</font></pre>
<P><A ID="I15" NAME="I15"><B>Implement CDierollDataPathProperty</B></A></P>
<P>There is some work to do in <font color="#008000">CDierollDataPathProperty</font> before changing <font color="#008000">CDierollCtrl::OnDraw()</font>. This class loads a bitmap, and this chapter is not going to explain most of what's involved in
reading a .BMP file into a <font color="#008000">CBitmap</font> object. The most important function is <font color="#008000">OnDataAvailable()</font>, which is in Listing 20.11. Add this function to the class by right-clicking CDierollCtrl in ClassView and
choosing Add Virtual Function. Select OnDataAvailable from the list on the left, and click Add and Edit, then type in this code.</P>
<P><I>Listing 20.11—DierollDataPathProperty.cpp—OnDataAvailable()</I></P>
<pre><font color="#008000">void CDierollDataPathProperty::OnDataAvailable(DWORD dwSize, DWORD grfBSCF)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CCachedDataPathProper
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -