65.9K
CodeProject 正在变化。 阅读更多。
Home

实现可重用的拖放类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (16投票s)

2001年6月5日

CPOL

2分钟阅读

viewsIcon

226348

downloadIcon

5090

本文提供了一组可重用的拖放类

引言

我尝试创建尽可能通用的拖放类。这就是我的想法。如果您希望为您的应用程序添加拖放支持,这是一个很好的起点。

演示项目包含各种剪贴板格式的示例代码

  • CF_TEXT
  • CF_HDROP
  • CF_BITMAP
  • CF_DIB
  • CF_ENHMETAFILE

以及 MEDIUMs

  • TYMED_HGLOBAL
  • TYMED_ISTREAM
  • TYMED_ENHMF
  • TYMED_GDI.

一些从静态窗口拖放图像的截图


(图 1. 从静态窗口拖动到 WordPad)

(图 2. 使用剪贴板)

(图 3. 将上述剪贴板内容粘贴到 WordPad 中)

用法

要将您的窗口启用为 DropTarget

  • CIDropTarget 派生一个类。
  • 重写 OnDrop。从此方法返回 true 或 false。如果为 true,基类将释放 medium。如果为 false,则不会释放 medium。
  • 调用 ::RegisterDragDrop 为您的窗口。
  • 通过调用 CIDropTarget::AddSuportedFormat 添加受支持的格式。
  • 可选地重写其他方法,例如 DragOverDragLeave
    我用它来突出显示树中的当前项目。

示例

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...
};

在您的窗口派生类中,创建一个 CTreeDropTarget 的成员。然后像这样初始化它

{
// ...
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);
// ...
}

这就是 drop target 的全部内容。

要将您的窗口启用为拖放源

  • 捕获启动拖放的 Windows 消息,例如 TVN_BEGINDRAG
  • 在消息函数处理程序中创建新的 CIDataObjectCIDropSource
  • 为这些格式创建剪贴板格式和 medium。
  • 调用 SetData 将剪贴板格式和 medium 添加到 DataObject SetData 的第二个参数指示 DataObject 是否应拥有 medium。如果设置为 TRUE,则 DataObject 拥有您的 medium,您无需释放它。否则,它将创建一个您的 medium 的副本,而不会释放您提供给它的那个。

示例

 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);
} 

要使用 shell 的拖动图像管理器(随 Windows 2000 附带)

如果您充当 drop target,则无需添加对此的支持。它被封装在 CIDropTarget 类中。
如果您充当 数据源

  • 在调用 ::DoDragDrop 之前创建一个 CDragSourceHelper 的实例。
  • 调用 CDragSourceHelper::InitializeFromWindow 或 CDragSourceHelper::InitializeFromBitmap。

通过剪贴板添加复制/粘贴也不是很多工作。

示例

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 
 // ...
}

参考文献

© . All rights reserved.