利用MAC实现对象拖放 一、对象拖放 对象拖放是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口之间、同一 应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)等操作的技术。 对象拖放是在操作系统的帮助下完成的。被拖动的对象首先指定使用的数据格式,并按 指定的数据格式提供数据;在拖放结束时,接收拖放对象的窗口按指定的数据格式提取 有关数据,并根据提取的数据生成对象。 二、MFC中用于对象拖放的类 MFC为实现对象拖放提供以下类: 1、C01eDataSouroe用于启动一次拖放操作,并向系统提供拖放对象的数据。类中重要 的成员函数有如下三种: a.设定提供数据的方式和使用的数据格式,提供数据的方式有两种,一种是即时方式, 另一种是延迟方式;延迟方式不需要立即提供数据,当需要提供数据时,系统将请求 数据,应当重载onRendrData()或其他虚函数,以响应对数据的请求。 数据格式可以是CF—TEXT等常用的剪贴板格式,也可以是自己利用 函数RegisterClipboardFormat(…)函数注册的特殊格式。 CacheData() 利用结构STGMEDIUM,为指定格式提供数据 CacheGlobalData() 利用全局句柄HGLOBAL,为指定格式提供数据 DelayRenderData() 使用延迟方式按指定格式数据提供数据 DelayRenderFileData() 使用延迟方式利用CFile为指定格式提供数据 b.响应请求,提供数据 onRenderFileData() 为延迟方式提供CFile型数据。 onRenderGlobalData() 为延迟方式提供HGLOBAL数据。 onRenerData 为延迟方式提供各种所支持的类型的数据。 c.实施拖放操作 DoDragDrop() 开始实施拖放操作 2、C01eDataTarget用于接收拖放对象的目标窗口,一个窗口要想能够接收拖放对象,必 须包含一个C01eDataTarget对象,并注册该对象。类中主要成员函数。 a.注册 Register() 并注册该对象,以便使窗口能够接收拖放对象 b.响应拖放过程中的动作(虚成员函数) onDragEnter() 当鼠标首次进入窗口时被调用 onDragLeave() 当鼠标移出窗口时被调用 onDragOver() 当鼠标在窗口内,重复调用被调用 onDrop() 当鼠标在窗口内落下被调用 虚函数onDragEnter()和OnDragOver()的返回值具有重要的含义,为以下数值之一; DROPEFFECT_MOVE:允许对象落在此窗口,落下时要删除原业的对象 DROPEFFECT_COPY:允许对象落在此窗口,落下时不删除原来的对象 DROPFFECT_NONE: 不允许对象落在此窗口 3、COleDataObject用于接收拖放对象,类中主要成员函数有: a.确定可以使用的数据格式 BeginEnumFormats() 为枚举数据格式作准备 GetNextFormat() 返回下一个数据格式 IsDataAvailable() 检查指定的数据格式是否可用 b.获取数据 GetData() 按指定数据格式,获得数据 GetFileData() 按指定数据格式,获得GFile型数据 GetGloba1Data() 按指定数据格式,获得HGLOBAL型数据 三、利用MFC实现对象拖放 1、拖放操作的启动 拖放操作的启动 拖放操作一般是从单击鼠标左键开始。在消息WM_LBUTTONDOWN的响应函数 onLButtonDown(…)中,首先要判定是否选定了某一对象,如果未选定或选定多个, 则不能进行拖放操作;如果选定了一个对象,则可以进行拖放操作。 要启动一次拖放操作,需要先准备一个COleDataSource对象。注意到类 COleClientIten和类COleServerItem都是从类COleDataSource上派生的,如果选定 的是COleClientItem对象或者是COleClientItem对象,则可以直接使用所选定的对象; 否则,需要生成一个COleDataSourxe对象,值得注意的是:需要象上文中所说的,应 该指定使用的数据格式,并按指定格式提供对象的有关数据。 下面给出准备数据源的例子: class myDataSource:public COleDataSource { public: CString str; protected: virtual BOOL onRenderFileData(LPFORMATETC,CFile*); //..... }; BOOL myDataSource::onRenderFileData(LPFORMATETC lpFormatEtc,CFile*pFile) { if(lpFormatEtc->cfFormat==CF_TEXT) { pFile,Write(str,str.GetLength()); return TRUE; } COleDataSource::OnRenderFileDataSource::OnRenderFileData(lpFormatEtc,pFile); return FALSE; } 程序中可以按如下方式,指定数据格式。 myDataSource*pItemDragDrop=new myDataSource; pItemDragDrop->str="0123456789ABCDEF"; pItemDragDrop->Delayrenderfiledata(CF_TEXT,NULL); 准备好COleDataSource对象之后,调用此对象的成员函数DoDragDrop(...)启动对象拖 放操作。 需要注意的是,函数DoDragDrop(...)并不立即返回,而是要等到鼠标按钮弹起之后。 从执行函数DoDragDrop(...)到从该函数返回,鼠标经过的窗口,接收到一系列的消息, 这些窗口可以根据消息作出相应的动作。 启运拖放操作,可以使用以下语句: int DragEffect=pItemDragDrop->DoDragDrop(rect,ptOffset,FALSE,DROPEFFECT_MOVE); 2、拖放对象的接收缺省情况下,一般的窗口是不能接收拖放对象的。要使窗口可以接收 拖放对象,需要在窗口类定义中加放成员对象COleDataTarget,并在生成窗口时调用函数 COledataTarger::register(). 例如: Class myView : public CScro11View { private: COleDataTarget oleTarget; protected: virtual int OnCreate(LPCREATESTRUCT); //..... } int myView::onCreate(LPCREATESTRUCT lpCreateStruct) { if(CScrollView::OnCreate(lpCreateStruct)==-1) return -1; dropTarget.Register(this); return 0; } 为实现拖放对象的接收,还应为消息 WM_DRAGENTER,WM_DRAGMOVE,WM_DRAGLEVER,WM_DRAGDROP提供响应函数。 消息WM_DRAGMOVE的响应函数OnDragMove(...)应根据鼠标在窗口中的位置,返回以下 数值: DROPEFFECT_MOVE——表明可以把对象复制到现在的窗口、现在的位置 DROPEFFECT_CIPY——表明可以把对象从原来的窗口、原来的位置移到现在的窗口、现 在的位置 DROPEFFECT_NONE——表明不能在该窗口的该位置放下 例如: DROPEFFECT myView::OnDragEnter(COleData ject*pDataobject,DWORD dwKeyState,CPoint point) { return DROPEFFECT_MOVE; } DROPEFFECT myView::OnDragOver(ColeDatalbject*pDataobject, DWORD dwKeyState,CPoint point) { return DROPEFFECT_MOVE: } 消息WM_DRAGDROP的响应函数OnDrop(COleDataject*pDataObject,DROPEFFECT dropEffect,CPoint point)应处理拖动对象放下后的工作。该函数的参数pDataobjec指 向一个COledataObject对象,利用指针,可以获取有关数据。该函数的一般实现是: a.检查对象的数据格式:利用COleDataObject::IsDataAvailable() b.按指定的格式获取数据:利用COleDataObject::GetFileData()等函数 c.建立对象(可能与原对象同,也可能不建立对象,仅使用对象中的数据):利用以上步 骤得到的数据。 例如: CString str; myDataSource*pMyData; if(IsDataAvailable(CF_TEXT)) { CFile file=GetFileData(CF_TEXT); file.Read(str,16); CClientDC dc(this); dc.TextOut(100,50,str,16); pMyData=new myDataSource; pMyData->str=str; } 对于COleClientItem或COleServerItem对象,可以按以下方法重建对象: COleClient*pItem=GetDocument()->CreateNewItem(); pItem->CreateForm(pDataObject) 3、拖放操作的结束 函数DoDragDrop()返回时,拖放过程结束。函DoDragDrop()的返回 值,表明了对象的拖放结果。 DROPEFFECT_MOVE:对象被放到他处,需删除原对象 DROPEFFECT_COPY:对象被复制到他处,不删除原对象 DROPEFFECT_NONE:未能实现拖效,无需删除原对象 例如: int DragEffect=pItemTracking->DoDranDrop(rect,ptOffset,FALSE,DROPEFFECT_MOVE); switch(DragEffect) { case DROPEFFECT_MOVE: delete pItemTracking; GetDocument()->UpdateAllltems(NULL); GetDocument()->UpdateAllliews(NULL); break; case DROPEFFECT_MOVE; case DROPEFFECT_NONE: default: break; }