实现可重用的拖放类






4.63/5 (16投票s)
本文提供了一组可重用的拖放类
引言
我尝试创建尽可能通用的拖放类。这就是我的想法。如果您希望为您的应用程序添加拖放支持,这是一个很好的起点。
演示项目包含各种剪贴板格式的示例代码
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
添加受支持的格式。 - 可选地重写其他方法,例如
DragOver
和DragLeave
。
我用它来突出显示树中的当前项目。
示例
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
。 - 在消息函数处理程序中创建新的
CIDataObject
和CIDropSource
。 - 为这些格式创建剪贴板格式和 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 // ... }
参考文献
- 示例来自 PSDK ..\Microsoft Platform SDK\Samples\WinUI\Shell\DragImg\
- SeeDIB.exe 显示 16 和 32 位每像素位图格式
- 如何在 Win32 中创建和播放增强型元文件