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

📄 ch14.htm

📁 Learning language of Visual C++6
💻 HTM
📖 第 1 页 / 共 5 页
字号:
around it and calls CRectTracker::Track(), which allows the user to resize the rectangle.
After the resizing, the item is sized to match the tracker rectangle and is redrawn.</P>
<P>SetSelection() is pretty straightforward. Add the definition of this public member
function to the header file, ShowStringView.h, and the code in Listing 14.30 to ShowStringView.cpp.</P>
<P>
<H4>Listing 14.30&#160;&#160;ShowStringView.cpp--CShowStringView::SetSelection()</H4>
<PRE>void CShowStringView::SetSelection(CShowStringCntrItem* item)
{
     // if an item is being edited in place, close it
     if ( item == NULL || item != m_pSelection)
     {
          COleClientItem* pActive =
               GetDocument()-&gt;GetInPlaceActiveItem(this);
          if (pActive != NULL &amp;&amp; pActive != item)
          {
               pActive-&gt;Close();
          }
     }
     Invalidate();
     m_pSelection = item;
</PRE>
<PRE>}
</PRE>
<P>When the selection is changed, any item that is being edited in place should be
closed. SetSelection() checks that the item passed in represents a change, and then
gets the active object from the document and closes that object. Then it calls for
a redraw and sets m_pSelection. Build and execute ShowString, insert an object, and
press Esc to stop in-place editing. Click and drag to move the inactive object, and
insert another. You should see something like Figure 14.11. Notice the resizing handles
around the bitmap, indicating that it is selected.</P>
<P><A HREF="javascript:popUp('14uvc11.gif')"><B>FIG. 14.11</B></A><B> </B><I>ShowString
can now hold multiple items, and the user can move and resize them intuitively.</I></P>
<P>You might have noticed that the cursor doesn't change as you move or resize. That's
because you didn't tell it to. Luckily, it's easy to tell it this: CRectTracker has
a SetCursor() member function, and all you need to do is call it when a WM_SETCURSOR
message is sent. Again, it should be the view that catches this message; right-click
CShowStringView in ClassView, and choose Add Windows Message Handler from the shortcut
menu. Click WM_SETCURSOR in the New Windows Messages/Events box on the left; then
click Add and Edit to add a handler function and edit the code immediately. Add the
code in Listing 14.31 to the empty function that was generated for you.</P>
<P>
<H4>Listing 14.31&#160;&#160;ShowStringView.cpp--CShowStringView::OnSetCursor()</H4>
<PRE>BOOL CShowStringView::OnSetCursor(CWnd* pWnd, UINT nHitTest,
     UINT message)
{
     if (pWnd == this &amp;&amp; m_pSelection != NULL)
     {
          CRectTracker track;
          SetupTracker(m_pSelection, &amp;track);
          if (track.SetCursor(this, nHitTest))
          {
               return TRUE;
          }
     }
     return CView::OnSetCursor(pWnd, nHitTest, message);
</PRE>
<PRE>}
</PRE>
<P>This code does nothing unless the cursor change involves this view and there is
a selection. It gives the tracking rectangle's SetCursor() function a chance to change
the cursor because the tracking object knows where the rectangle is and whether the
cursor is over a boundary or sizing handle. If SetCursor() didn't change the cursor,
this code lets the base class handle it. Build and execute ShowString, and you should
see cursors that give you feedback as you move and resize.</P>
<P>
<H3><A NAME="Heading9"></A>Handling Double-Clicks</H3>
<P>When a user double-clicks a contained item, the <I>primary</I> <I>verb</I> should
be called. For most objects, the primary verb is to Edit in place, but for some,
such as sound files, it is Play. Arrange as before for CShowStringView to catch the
WM_LBUTTONDBLCLK message, and add the code in Listing 14.32 to the new function.</P>
<P>
<H4>Listing 14.32&#160;&#160;ShowStringView.cpp--CShowStringView::OnLButtonDblClk()</H4>
<PRE>void CShowStringView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
     OnLButtonDown(nFlags, point);
     if( m_pSelection)
     {
          if (GetKeyState(VK_CONTROL) &lt; 0)
          {
               m_pSelection-&gt;DoVerb(OLEIVERB_OPEN, this);
          }
          else
          {
               m_pSelection-&gt;DoVerb(OLEIVERB_PRIMARY, this);
          }
     }
     CView::OnLButtonDblClk(nFlags, point);
</PRE>
<PRE>}
</PRE>
<P>First, this function handles the fact that this item has been clicked; calling
OnLButtonDown() draws the tracker rectangle, sets m_pSelection, and so on. Then,
if the user holds down Ctrl while double-clicking, the item is opened; otherwise,
the primary verb is called. Finally, the base class function is called. Build and
execute ShowString and try double-clicking. Insert an object, press Esc to stop editing
it, move it, resize it, and double-click it to edit in place.</P>
<P>
<H2><A NAME="Heading10"></A>Implementing Drag and Drop</H2>
<P>The last step to make ShowString a completely up-to-date ActiveX container application
is to implement drag and drop. The user should be able to grab a contained item and
drag it out of the container, or hold down Ctrl while dragging to drag out a copy
and leave the original behind. The user should also be able to drag items from elsewhere
and drop them into this container just as though they had been inserted through the
Clipboard. In other words, the container should operate as a <I>drag source</I> and
a <I>drop target</I>.</P>
<P>
<H3><A NAME="Heading11"></A>Implementing a Drag Source</H3>
<P>Because CShowStringCntrItem inherits from COleClientItem, implementing a drag
source is really easy. By clicking a contained object, edit these lines at the end
of CShowStringView::OnLButtonDown() so that it resembles Listing 14.33. The new lines
are in bold type.</P>
<P>
<H4>Listing 14.33&#160;&#160;CShowStringView::OnLButtonDown()--Implementing a Drag
Source</H4>
<PRE>void CShowStringView::OnLButtonDown(UINT nFlags, CPoint point)
{
    CShowStringCntrItem* pHitItem = HitTest(point);
    SetSelection(pHitItem);
    if (pHitItem == NULL)
        return;
    CRectTracker track;
    SetupTracker(pHitItem, &amp;track);
    UpdateWindow();
<B>    if (track.HitTest(point) == CRectTracker::hitMiddle)</B>
<B>    {</B>
<B>        CRect rect =  pHitItem-&gt;m_rect;</B>
<B>        CClientDC dc(this);</B>
<B>        OnPrepareDC(&amp;dc);</B>
<B>        dc.LPtoDP(&amp;rect); // convert logical rect to device rect</B>
<B>        rect.NormalizeRect();</B>
<B>        CPoint newpoint = point - rect.TopLeft();</B>
<B>        DROPEFFECT dropEffect = pHitItem-&gt;DoDragDrop(rect, newpoint);</B>
<B>        if (dropEffect == DROPEFFECT_MOVE)</B>
<B>        {</B>
<B>            Invalidate();</B>
<B>            if (pHitItem == m_pSelection)</B>
<B>            {</B>
<B>                m_pSelection = NULL;</B>
<B>            }</B>
<B>            pHitItem-&gt;Delete();</B>
<B>        }</B>
<B>    }</B>
<B>    else</B>
<B>    {</B>
        if (track.Track(this,point))
        {
            Invalidate();
            pHitItem-&gt;m_rect = track.m_rect;
            GetDocument()-&gt;SetModifiedFlag();
        }
    }
</PRE>
<PRE>}
</PRE>
<P>This code first confirms that the mouse click was inside the tracking rectangle,
rather than on the sizing border. It sets up a temporary CRect object that will be
passed to DoDragDrop() after some coordinate scheme conversions are complete. The
first conversion is from logical to device units, and is accomplished with a call
to CDC::LPtoDP(). In order to call this function, the new code must create a temporary
device context based on the CShowStringView for which OnLButtonDown() is being called.
Having converted rect to device units, the new code normalizes it and calculates
the point within the rectangle where the user clicked.</P>
<P>Then the new code calls the DoDragDrop() member function of CShowStringCntrItem,
inherited from COleClientItem and not overridden. It passes in the converted rect
and the offset of the click. If DoDragDrop() returns DROPEFFECT_MOVE, the item was
moved and needs to be deleted. The code to handle a drop, which is not yet written,
will create a new container item and set it as the current selection. This means
that if the object was dropped elsewhere in the container, the current selection
will no longer be equal to the hit item. If these two pointers are still equal, the
object must have been dragged away. If it was dragged away, this code sets m_pSelection
to NULL. In either case, pHitItem should be deleted.</P>
<P>Build and execute ShowString, insert a new object, press Esc to stop editing in
place, and then drag the inactive object to an ActiveX container application such
as Microsoft Excel. You can also try dragging to the desktop. Be sure to try dragging
an object down to the taskbar and pausing over the icon of a minimized container
application, and then waiting while the application is restored so that you can drop
the object.</P>
<P>
<H3><A NAME="Heading12"></A>Implementing a Drop Target</H3>
<P>It is harder to make ShowString a drop target (it could hardly be easier). If
you dragged a contained item out of ShowString and dropped it into another container,
try dragging that item back into ShowString. The cursor changes to a circle with
a slash through it, meaning &quot;you can't drop that here.&quot; In this section,
you make the necessary code changes that allow you to drop it there after all.</P>
<P>You need to register your view as a place where items can be dropped. Next, you
need to handle the following four events that can occur:</P>

<UL>
	<LI>An item might be dragged across the boundaries of your view. This action will
	require a cursor change or other indication you will take the item.
	<P>
	<LI>In the view, the item will be dragged around within your boundaries, and you
	should give the user feedback about that process.
	<P>
	<LI>That item might be dragged out of the window again, having just passed over your
	view on the way to its final destination.
	<P>
	<LI>The user may drop the item in your view.
</UL>

<H3><A NAME="Heading13"></A>Registering the View as a Drop Target</H3>
<P>To register the view as a drop target, add a COleDropTarget member variable to
the view. In ShowStringView.h, add this line to the class definition:</P>
<P>
<PRE>     COleDropTarget m_droptarget;
</PRE>
<P>To handle registration, override OnCreate() for the view, which is called when
the view is created. Arrange for CShowStringView to catch the WM_CREATE message.
Add the code in Listing 14.34 to the empty function generated for you.</P>
<P>
<H4>Listing 14.34&#160;&#160;ShowStringView.cpp--CShowStringView::OnCreate()</H4>
<PRE>int CShowStringView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
     if (CView::OnCreate(lpCreateStruct) == -1)
          return -1;
     if (m_droptarget.Register(this))
     {
          return 0;
     }
     else
     {
          return -1;
     }
</PRE>
<PRE>}
</PRE>
<P>OnCreate() returns 0 if everything is going well and -1 if the window should be
destroyed. This code calls the base class function and then uses COleDropTarget::Register()
to register this view as a place to drop items.</P>
<P>
<H3><A NAME="Heading14"></A>Setting Up Function Skeletons and Adding Member Variables</H3>
<P>The four events that happen in your view correspond to four virtual functions
you must override: OnDragEnter(), OnDragOver(), OnDragLeave(), and OnDrop(). Right-click
CShowStringView in ClassView and choose Add Virtual Function to add overrides of
these functions. Highlight OnDragEnter() in the New Virtual Functions list, click
Add Handler, and repeat for the other three functions.</P>
<P>OnDragEnter() sets up a <I>focus rectangle</I> that shows the user where the item
would go if it were dropped here. This is maintained and drawn by OnDragOver(). But
first, a number of member variables related to the focus rectangle must be added
to CShowStringView. Add these lines to ShowStringView.h, in the public section:</P>
<P>
<PRE>     CPoint m_dragpoint;
     CSize m_dragsize;
     CSize m_dragoffset;
</PRE>
<P>A data object contains a great deal of information about itself, in various formats.
There is, of course, the actual data as text, <I>device independent bitmap (DIB)</I>,
or whatever other format is appropriate. But there is also information about the
object itself. If you request data in the Object Descriptor format, you can find
out the size of the item and where on the item the user originally clicked, and the
offset from the mouse to the upper-left corner of the item. These formats are generally
referred to as <I>Clipboard formats</I> because they were originally used for Cut
and Paste via the Clipboard.</P>
<P>To ask for this information, call the data object's GetGlobalData() member function,
passing it a parameter that means &quot;Object Descriptor, please.&quot; Rather than
build this parameter from a string every time, you build it once and store it in
a static member of the class. When a class has a static member variable, every instance
of the class looks at the same memory location to see that variable. It is initialized
(and memory is allocated for it) once, outside the class.</P>
<P>Add this line to ShowStringView.h:</P>
<P>
<PRE>     static CLIPFORMAT m_cfObjectDescriptorFormat;
</PRE>
<P>In ShowStringView.cpp, just before the first function, add these lines:</P>
<P>
<PRE>CLIPFORMAT CShowStringView::m_cfObjectDescriptorFormat =
     (CLIPFORMAT) ::RegisterClipboardFormat(&quot;Object Descriptor&quot;);
</PRE>
<P>This makes a CLIPFORMAT from the string &quot;Object Descriptor&quot; and saves
it in the static member variable for all instances of this class to use. Using a
static member variable speeds up dragging over your view.</P>
<P>Your view doesn't accept any and all items that are dropped on it. Add a BOOL
member variable to the view that indicates whether it accepts the item that is now
being dragged over it:</P>
<P>
<PRE>     BOOL m_OKtodrop;
</PRE>
<P>There is one last member variable to add to CShowStringView. As the item is dragged
across the view, a focus rectangle is repeatedly drawn and erased. Add another BOOL
member variable that tracks the status of the focus rectangle:</P>
<P>
<PRE>     BOOL m_FocusRectangleDrawn;
</PRE>
<P>Initialize m_FocusRectangle

⌨️ 快捷键说明

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