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

📄 ch07.htm

📁 用VC开发ACTIVEX书籍和随书源码- Develops the ACTIVEX books and along with the book source code with VC
💻 HTM
📖 第 1 页 / 共 5 页
字号:
       HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(TCHAR)
     <BR>
      * lLength);<BR>
     <BR>
       // lock the memory down<BR>
       LPTSTR lpTempBuffer = (LPTSTR) ::GlobalLock(hGlobal);<BR>
       // copy the string<BR>
       for(long lCount = 0; lCount &lt; lLength - 1; lCount++)<BR>
       lpTempBuffer[lCount] = m_cstrCaption.GetAt(lCount);<BR>
       // null terminate the string<BR>
       lpTempBuffer[lCount] = `\0';<BR>
       // unlock the memory<BR>
       ::GlobalUnlock(hGlobal);<BR>
       // cache the data <BR>
       opOleDataSource-&gt;CacheGlobalData(CF_TEXT, hGlobal);<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF">
</FONT></PRE>
<P><B>Enabling a Control as a Clipboard Target</B> The opposite of being a Clipboard
source is being a Clipboard target. First you need to update the <TT>CMFCControlWinCtrl</TT><B>
</B>class to include two new helper functions (see Listing 7.19).
<H3><A NAME="Heading26"></A>Listing 7.19 MFCCONTROLWINCTL.H--Clipboard Target Support
Helper Function Prototypes</H3>
<P><FONT COLOR="#0066FF"><TT>. . .<BR>
       void GetDataFromClipboard(void);<BR>
. . .<BR>
       BOOL GetDataFromTransfer(COleDataObject * opOleDataObject);<BR>
};<BR>
. . .</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P>Getting data from the Clipboard is almost as simple as it is to put the data on
the Clipboard in the first place. <TT>GetDataFromClipboard</TT> uses the <TT>COleDataObject</TT>
MFC class to attach to the Clipboard and, if successful, passes the object to the
<TT>GetDataFromTransfer</TT> helper function (see Listing 7.20).
<H3><A NAME="Heading27"></A>Listing 7.20 MFCCONTROLWINCTL.CPP--GetDataFromClipboard
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CMFCControlWinCtrl::GetDataFromClipboard(void)<BR>
{<BR>
       // get a data object<BR>
       COleDataObject oOleDataObject;<BR>
       // attach it to the clipboard<BR>
       if(!oOleDataObject.AttachClipboard())<BR>
               return;<BR>
       // transfer the data to the control<BR>
       this-&gt;GetDataFromTransfer(&amp;oOleDataObject);<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P><TT>GetDataFromTansfer</TT> enumerates all of the available formats in the <TT>COleDataObject</TT>
object using <TT>BeginEnumFormats</TT> (see Listing 7.21). To optimize the search
a little bit, you should first see whether the Clipboard even contains any data that
you can use. In this case, you are looking for the <TT>CF_TEXT</TT> format. The implementation
contains a simple <TT>while</TT> loop that will execute as many times as there are
formats in the <TT>COleDataObject</TT> object. When you locate a <TT>CF_TEXT</TT>
format, you retrieve its global memory object with the function <TT>GetGlobalData</TT>
and copy the data that it points to into the control. Do not destroy the data that
was retrieved with this method--you are not its owner; the <TT>COleDataObject</TT>
is.
<H3><A NAME="Heading28"></A>Listing 7.21 MFCCONTROLWINCTL.CPP--GetDataFromTransfer
Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>BOOL CMFCControlWinCtrl::GetDataFromTransfer(COleDataObject
* opOleDataObject)<BR>
{    <BR>
       BOOL bReturn = FALSE;<BR>
       // prepare for an enumeration of the clipboard formats available<BR>
       opOleDataObject-&gt;BeginEnumFormats();<BR>
       // is there a text format available <BR>
       if(opOleDataObject-&gt;IsDataAvailable(CF_TEXT))<BR>
       {<BR>
               FORMATETC etc;<BR>
               // while there are formats to enumerate<BR>
               while(opOleDataObject-&gt;GetNextFormat(&amp;etc))<BR>
               {<BR>
                       // is this a format that we are looking for?<BR>
                       if(etc.cfFormat == CF_TEXT)<BR>
                       {<BR>
                              // get the global data for this format<BR>
                              HGLOBAL hGlobal = opOleDataObject-&gt;GetGlobalData
                                 (etc.cfFormat, &amp;etc);<BR>
                              // lock down the memory<BR>
                              LPTSTR lpTempBuffer = (LPTSTR) ::GlobalLock       
                          (hGlobal);<BR>
                              // store the data<BR>
                              m_cstrCaption = lpTempBuffer;<BR>
                              // call the global routine<BR>
                              this-&gt;FireChange();<BR>
                              // unlock the memory<BR>
                              ::GlobalUnlock(hGlobal);<BR>
                              // return success<BR>
                              bReturn = TRUE;<BR>
                         }<BR>
                 }<BR>
        }<BR>
       // if we found a format<BR>
       if(bReturn == TRUE)<BR>
               // force the control to repaint itself<BR>
               this-&gt;InvalidateControl(NULL);<BR>
       // return the result<BR>
       return bReturn;<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P><B>Custom Clipboard Formats</B><SPACER TYPE="HORIZONTAL" SIZE="10"><B> </B>The
Clipboard is able to support custom formats, as well as built-in formats, defined
by the operating system. Fortunately, the implementation of custom formats for the
Clipboard is the same as for Drag and Drop. First you will learn how to support Drag
and Drop and then how to support custom formats.
<H3><A NAME="Heading29"></A>Drag and Drop Support</H3>
<P>The fundamentals of Drag and Drop support are very similar to Clipboard support
and rely on the same MFC classes, <TT>COleDataSource</TT> and <TT>COleDataObject</TT>,
for their implementation. Since you have broken your code into separate functions--that
is, the Clipboard specific code is isolated from the basic data transfer functions--most
of your implementation is complete. <B><BR>
<BR>
Using Built-In Drag and Drop Formats </B><SPACER TYPE="HORIZONTAL" SIZE="10">Since
Drag and Drop is essentially a Clipboard transfer, with fewer steps involved, Drag
and Drop uses the same built-in data formats as the Clipboard transfers do. See the
list of supported formats earlier in this chapter. As with Clipboard transfers, there
are two sides to the Drag and Drop coin. An application can be a Drag and Drop source
or a Drag and Drop target, or both.<BR>
<BR>
<B><I>Enabling a Control as a Drag and Drop Source</I></B><SPACER TYPE="HORIZONTAL"
SIZE="10"><B><I> </I></B>To qualify as a Drag and Drop source, your only implementation
requirements are that you create a <TT>COleDataSource</TT> object, call the method
<TT>DoDragDrop</TT>, and have some way of initiating the Drag and Drop operation
in the first place. In addition to the <TT>IDataObject</TT><B><I> </I></B>and <TT>IEnumFORMATETC</TT>
interfaces, the <TT>COleDataSource</TT> defines the <TT>IDropSource</TT> interface,
all of which are necessary for Drag and Drop source support. The first step is to
initiate a Drag and Drop operation. You are going to use the left mouse button down
event, provided by MFC, to initiate the Drag and Drop operation. Open the ClassWizard,
and select the Message Maps tab. Select the class <TT>CMFCControlWinCtrl</TT>, and
double-click the <TT>WM_LBUTTONDOWN</TT> message to add the <TT>OnLButtonDown</TT>
function (see fig. 7.3).</P>
<P>To open the source file and add your code, double-click the <TT>OnLButtonDown</TT>
function in the Member <U>f</U>unctions list box. <BR>
<BR>
<A HREF="Art/07/w_fig03.jpg"><B>FIG. 7.3</B></A> <I><BR>
Add the <TT>WM_LBUTTONDOWN</TT> message map.</I></P>
<P>The <TT>OnLButtonDown</TT> implementation is similar to the Clipboard method <TT>CopyDataToClipboard</TT>
(see Listing 7.22). Again, you are using a <TT>COleDataSource</TT> object and loading
it with your data with the <TT>PrepareDataForTransfer</TT> call.</P>
<P>To actually initiate the Drag and Drop operation, you call <TT>DoDragDrop</TT>
specifying the constant <TT>DROPEFFECT_COPY</TT>, which indicates that this is a
copy operation. The constant <TT>DROPEFFECT_COPY</TT> is used for two purposes. The
first, and most obvious to the user, is that the mouse cursor will change to indicate
that a copy drag is in progress. The second is to inform the drop target as to the
intent of the drop operation.
<H3><A NAME="Heading30"></A>Listing 7.22 MFCCONTROLWINCTL.CPP--OnLButtonDown Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>void CMFCControlWinCtrl::OnLButtonDown(UINT nFlags,
CPoint point) <BR>
{<BR>
        COleDataSource oOleDataSource;<BR>
        // call the common data preparation function<BR>
        this-&gt;PrepareDataForTransfer(&amp;oOleDataSource);<BR>
        // start the Drag and Drop operation<BR>
        oOleDataSource.DoDragDrop(DROPEFFECT_COPY);<BR>
        // call the base class implementation<BR>
        COleControl::OnLButtonDown(nFlags, point);<BR>
}</TT></FONT>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P>Now that the control has been enabled as a Drag and Drop source, it only makes
sense to enable it as a Drag and Drop target. <B><I><BR>
<BR>
Enabling a Control as a Drop Target </I></B><SPACER TYPE="HORIZONTAL" SIZE="10">To
qualify as a Drag and Drop target, a control must register itself as a Drag and Drop
target and must implement the <TT>IDropTarget</TT> interface. The MFC class <TT>COleDropTarget</TT>
provides the needed interface definition. However, it is not enough to rely on the
default implementation of the <TT>COleDropTarget</TT> class to enable the control
as a Drag and Drop target. You are required to inherit your own specialized version
of the class so that you can override some of its functions. Call the new class <TT>CMyOleDropTarget</TT>,
and add it to the <TT>CMFCControlWinCtl</TT> class (see Listing 7.23). You need to
overload the methods <TT>OnDragOver</TT> and <TT>OnDrop</TT> for your specific implemen-
tation as a drop target. Also added is a member variable of type <TT>CMyOleDropTarget</TT>
called <TT>oMyOleDropTarget</TT>.</P>
<P>The class <TT>CMyOleDropTarget</TT> needs to be a friend of the CMFCControlWinCtrl
class so that the <TT>CMyOleDropTarget</TT> class may call the general <TT>GetDataFromTransfer</TT>
function to store the data in the control.
<H3><A NAME="Heading31"></A>Listing 7.23 MFCCONTROLWINCTL.H--CMyOleDropTarget Class
Declaration Added to the CMFCControlWinCtl Class</H3>
<P><FONT COLOR="#0066FF"><TT>class CMyOleDropTarget: public COleDropTarget<BR>
{<BR>
public:<BR>
           CMFCControlWinCtrl * opMFCControlWinCtrl;<BR>
           DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD 
                   dwKeyState, CPoint point);<BR>
           BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT      
            dropEffect, CPoint point);<BR>
} oMyOleDropTarget;<BR>
friend CMyOleDropTarget;<BR>
</TT></FONT></P>

<P>As we stated earlier, an application must register itself with the operating system
in order to be a valid Drag and Drop target. Register the control as a Drag and Drop
target using the function, <TT>Register</TT>, in your <TT>OnCreate</TT> method for
the control. To add the <TT>OnCreate</TT> function to the class, you use the ClassWizard.
Open the ClassWizard, and select the Message Maps tab. Select the class <TT>CMFCControlWinCtrl</TT>,
and double-click the <TT>WM_CREATE</TT> message to add the <TT>OnCreate</TT> function
to your class (see fig. 7.4). <B><BR>
<BR>
</B><A HREF="Art/07/w_fig04.jpg"><B>FIG. 7.4</B></A> <I><BR>
Add the WM_CREATE message map.</I></P>

<P>To add your code, open the source file by double-clicking the <TT>OnCreate</TT>
function in the Member <U>f</U>unctions list box.</P>

<P><TT>Register</TT> is the only call that is required to enable your control as
a drop target (see Listing 7.24). The member variable <TT>opMFCControlWinCtrl</TT>
is set with a reference to the control so you can call the general method <TT>GetDataFromTransfer</TT>
to put the data into your control; this is specific to your implementation and not
a requirement for Drag and Drop target support.
<H3><A NAME="Heading32"></A>Listing 7.24 MFCCONTROLWINCTL.CPP--OnCreate Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>int CMFCControlWinCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
<BR>
{<BR>
       if (COleControl::OnCreate(lpCreateStruct) == -1)<BR>
              return -1;<BR>
 <BR>
       // let's register ourselves as drop targets<BR>
       oMyOleDropTarget.Register(this);<BR>
       // store a reference to the control so we can communicate back to the    
        control<BR>
       oMyOleDropTarget.opMFCControlWinCtrl = this;<BR>
 <BR>
       return 0;<BR>
}<BR>
</TT></FONT></P>

<P>The <TT>OnDragOver</TT> function is used to instruct Windows that your control
is a valid or invalid drop target for the current drag operation (see Listing 7.25).
The implementation of <TT>OnDragOver</TT> first looks to see whether the mouse button
is being held down. If it is, <TT>OnDragOver</TT> then looks for the availability
of the CF_TEXT format. If it finds the <TT>CF_TEXT</TT> format, the <TT>OnDragOver</TT>
function returns the constant <TT>DROPEFFECT_COPY</TT>, indicating to Windows that
the control is a valid drop target for the particular drop operation that is currently
in effect. Otherwise, <TT>OnDragOver</TT> returns <TT>DROPEFFECT_NONE</TT>, indicating
that a drop should not be allowed.
<H3><A NAME="Heading33"></A>Listing 7.25 MFCCONTROLWINCTL.CPP--OnDragOver Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>DROPEFFECT CMFCControlWinCtrl::CMyOleDropTarget::OnDragOver(CWnd*
pWnd,        <BR>
C

⌨️ 快捷键说明

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