扩展COleDropTarget类来支持任意窗口拖放
作者:沈阳市热电厂汽机分场 - 王加宝
| 本文详细论述了拖放的基本原理并提供一个支持窗口拖放的普遍类COleDropTargetEx,任何需要提供拖放的窗口包含此类后,将响应拖放消息函数加入,便可接收拖放。此类利用Windows消息来支持拖放,机制不同于COleDropTarget类与CView类那种直接的搭配关系,因此较以往的拖放方法简便、灵活,代码重用性非常好。 本文示例工程 19.1K ![]() 这是本文示例代码的运行效果图 一、拖放原理及MFC类库对拖放的支持 拖放(Drag and Drop)是OLE的一部分,是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口之间、同一应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)等操作的技术。 MFC为实现对象拖放提供了如下类:COleDataSource、COleDropSource、COleDropTarget、COleDataObject。对于上述几个类的用法,读者可参考有关资料。因拖放操作中的启动拖放部分,实现较模式化,很多文献都有详细的实现,本文在此不再赘述。这里着重说明MFC拖放操作中接收部分的实现原理,以使读者了解为何要扩展MFC拖放类的功能。 MFC通过提供COleDropTarget和CView类来支持拖放操作的接收。在CView及其继承类中创建COleDropTarget类对象,并在视图窗口初始化时,调用其成员函数Register(),以此在系统中注册该视图窗口为拖放接收窗口。当进行拖放操作的鼠标指针处于视图窗口范围内时,COleDropTarge类的OnDragEnter、OnDragOver、OnDropEx、OnDrop等成员函数被依次调用,这些函数默认调用与其相对应的CView类成员函数OnDragEnter、OnDragOver、OnDropEx、OnDrop等,在这些CView类成员函数中,用户可对拖动的过程及结果进行控制。但MFC这种内在的对拖放的实现是很不够的,一个用户界面友好的应用程序,很多时候要求不仅视图窗口支持拖放,而且对话框以及编辑框等控制窗口也需要拖放的支持。虽然现在已经有一些拖放目标类的扩展类了,但通常都是需要按照CView类对拖放的实现模式来实现这些窗口类,再在COleDropTarge继承类的响应拖放函数中利用RTTI(Run-time type information)来调用这些特定的窗口类拖放响应函数。而利用RTTI机制不可避免地会使拖放类只支持特定的窗口类,如果要增加新的可支持拖放的窗口类,则必须改写已实现的COleDropTarge继承类,这种情况是我们所不愿看到的。如果直接在COleDropTarge继承类中处理拖放呢?显然,只会造就一个针对性更强的类。针对这种情况,需要运用其它方式来支持无类型要求的窗口类拖放操作。 二、拖放扩展类运行原理 三、实例实现 public:virtual BOOL Register(); // Generated message map functionsprotected: COleDropTargetEx m_dropEx;virtual BOOL OnDrop(WPARAM pDropInfoClass, LPARAM lParm); virtual DROPEFFECT OnDropEx(WPARAM pDropInfoClass, LPARAM lParm); virtual DROPEFFECT OnDragOver(WPARAM pDropInfoClass,LPARAM lParm);在实现文件中添加消息映射如下: BEGIN_MESSAGE_MAP(CDropEdit, CEdit) //{{AFX_MSG_MAP(CDropEdit) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP ON_MESSAGE(DROPM_DRAGOVER,OnDragOver) ON_MESSAGE(DROPM_DROPEX,OnDropEx) ON_MESSAGE(DROPM_DROP,OnDrop) END_MESSAGE_MAP() 在实现文件中消息响应函数定义如下: /////////////////////////////////////////////////////////////////////////////// CDropEdit message handlersBOOL CDropEdit::Register(){ return m_dropEx.Register( this );}DROPEFFECT CDropEdit::OnDragOver(WPARAM pDropInfoClass, LPARAM lParm){ COleDropInfo* pInfo = (COleDropInfo* )pDropInfoClass; ASSERT(pInfo->IsKindOf(RUNTIME_CLASS(COleDropInfo))); if( pInfo->pDataObject->IsDataAvailable( CF_TEXT ) ) return DROPEFFECT_COPY; else return DROPEFFECT_NONE;}DROPEFFECT CDropEdit::OnDropEx(WPARAM pDropInfoClass, LPARAM lParm){ return (DROPEFFECT)-1;}BOOL CDropEdit::OnDrop(WPARAM pDropInfoClass, LPARAM lParm){ COleDropInfo* pInfo = (COleDropInfo* )pDropInfoClass; ASSERT(pInfo->IsKindOf(RUNTIME_CLASS(COleDropInfo))); if( pInfo->pDataObject->IsDataAvailable( CF_TEXT ) )//拖动对象为文本 { HGLOBAL hMem = pInfo->pDataObject->GetGlobalData( CF_TEXT ); char* lp = (char *)GlobalLock((HGLOBAL) hMem);//lock source if ( lp != NULL) { //Set Windows title with Drop text SetWindowText( lp ); } GlobalUnlock( hMem );//unlock source return TRUE; } else return FALSE;} 现在,一个支持拖放的编辑框就做好了。那么把它放到对话框中测试一下。 添加一个编辑控制m_dropEdit到对话框模板中,使用ClassWizard声明该编辑控制为CDropEdit类型。在对话框类的OnInitDialog()函数中注册该编辑对象为拖放目标窗口。 BOOL CDropExDemoDlg::OnInitDialog(){ //其它内容 if( !m_dropEdit.Register() ) TRACE("register drop edit faile"); //其它内容} 最后,别忘了初始化OLE。在应用程序类初始化函数中添加OLE初始化代码。 BOOL CDropExDemoApp::InitInstance(){ //其它内容 if( !AfxOleInit() ) TRACE("Ole init faile"); //其它内容} 现在,编译并运行程序。从VC ++ 6.0编辑窗口中选择一词,用鼠标拖动其到编辑控制上并释放鼠标左键,编辑控制中内容变为拖动来的文本。至此,测试成功完成。四、总结 参考文献: 沈阳市铁西区北二中路26号沈阳热电厂汽机分场(110026) Email:ShyWJB@263.net |




相关教程