Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Implementing Reusable Drag & Drop Classes

0.00/5 (No votes)
4 Jun 2001 6  
This article provides a set of reusable drag and drop classes

Introduction

I tried to create as generic a Drag and Drop classes as possible. Here is what I came up with. I think it's a good starting point if you're looking to add drag and drop support to your app.

The demo project has sample code for various clipboard formats:

  • CF_TEXT
  • CF_HDROP
  • CF_BITMAP
  • CF_DIB
  • CF_ENHMETAFILE

and MEDIUMs

  • TYMED_HGLOBAL
  • TYMED_ISTREAM
  • TYMED_ENHMF
  • TYMED_GDI.

Some screenshots of image drag and drop from static window:


(Fig. 1. Dragging from static window to WordPad)

(Fig. 2. Using Clipboard)

(Fig. 3. Pasting the above clipboard contents into WordPad)

Usage:

To enable your window as a DropTarget:

  • Derive a class from CIDropTarget.
  • Override OnDrop. Return true or false from this method. If true, base class will free the medium. If false, it won't free the medium.
  • Call ::RegisterDragDrop for your window.
  • Add Supported formats by calling CIDropTarget::AddSuportedFormat.
  • Optionally override other methods such as DragOver and DragLeave.
    I used it for the tree to highlight the current item.

Example:

class CTreeDropTarget : public CIDropTarget
{
public:
      virtual bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD *pdwEffect)
      {
            if(pFmtEtc->cfFormat == CF_TEXT && medium.tymed == TYMED_HGLOBAL)
            {
              // Handle it

            }
          return true;
      }
     // etc...

};

In your Window derived class create a member of CTreeDropTarget. Then initialize it like this:

{
// ...

m_pDropTarget = new CTreeDropTarget(m_hWnd);
RegisterDragDrop(m_hWnd,m_pDropTarget);
// create the supported formats:

FORMATETC ftetc={0}; 
ftetc.cfFormat = CF_TEXT; 
ftetc.dwAspect = DVASPECT_CONTENT; 
ftetc.lindex = -1; 
ftetc.tymed = TYMED_HGLOBAL; 
m_pDropTarget->AddSuportedFormat(ftetc); 
ftetc.cfFormat=CF_HDROP; 
m_pDropTarget->AddSuportedFormat(ftetc);
// ...

}

That's all for drop target.

To enable your window as the Drag and Drop source:

  • Catch the Windows message that initiates the drag and drop such as TVN_BEGINDRAG.
  • In the message function handler create new CIDataObject and CIDropSource.
  • Create the clipboard formats and medium for those formats.
  • Call SetData to add the clipboard formats and medium to DataObject. Second parameter to SetData indicates if DataObject should take the ownership of medium or not. If set to TRUE, then DataObject takes the ownership of your medium, you don't need to free it. Otherwise it will make a copy of your medium without releasing the one you gave it.

Eaxmple:

 LRESULT OnBegindrag(...)
{
   CIDropSource* pdsrc = new CIDropSource;
   CIDataObject* pdobj = new CIDataObject(pdsrc);
   // Init the supported format

   FORMATETC fmtetc = {0}; 
   fmtetc.cfFormat = CF_TEXT; 
   fmtetc.dwAspect = DVASPECT_CONTENT; 
   fmtetc.lindex = -1; 
   fmtetc.tymed = TYMED_HGLOBAL;
  // Init the medium used

  STGMEDIUM medium = {0};
  medium.tymed = TYMED_HGLOBAL;
  // medium.hGlobal = init to something

  // Add it to DataObject

  pdobj->SetData(&fmtetc,&medium,TRUE); // Release the medium for me

  // add more formats and medium if needed

  // Initiate the Drag & Drop

  ::DoDragDrop(pdobj, pdsrc, DROPEFFECT_COPY, &dwEffect);
} 

To use the shell's drag image manager (comes with Windows 2000):

You don't need to add the support for it if you are acting as drop target. It is encapsulated in CIDropTarget class.
If you're acting as data source:

  • Create an instance of CDragSourceHelper before calling ::DoDragDrop.
  • Call CDragSourceHelper::InitializeFromWindow or CDragSourceHelper::InitializeFromBitmap.

Adding the Copy/Paste through clipboard is not much work either.

Example:

LRESULT OnContextMenu(...)
{
  // ...

   CIDataObject* pdobj = new CIDataObject(NULL);  
   // Init FORMATETC and STGMEDIUM just like before

   // Add the format and medium to Dataobject

  pdobj->SetData(&fmtetc,&medium,TRUE);
  // Add data to clipboard

  OleSetClipboard(pdobj);
  OleFlushClipboard(); //render the data on clipboard, so it's available even if we close the app 

 // ...

}

References:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here