实现drop目标对象.docx

上传人:b****3 文档编号:5705080 上传时间:2023-05-09 格式:DOCX 页数:13 大小:361.25KB
下载 相关 举报
实现drop目标对象.docx_第1页
第1页 / 共13页
实现drop目标对象.docx_第2页
第2页 / 共13页
实现drop目标对象.docx_第3页
第3页 / 共13页
实现drop目标对象.docx_第4页
第4页 / 共13页
实现drop目标对象.docx_第5页
第5页 / 共13页
实现drop目标对象.docx_第6页
第6页 / 共13页
实现drop目标对象.docx_第7页
第7页 / 共13页
实现drop目标对象.docx_第8页
第8页 / 共13页
实现drop目标对象.docx_第9页
第9页 / 共13页
实现drop目标对象.docx_第10页
第10页 / 共13页
实现drop目标对象.docx_第11页
第11页 / 共13页
实现drop目标对象.docx_第12页
第12页 / 共13页
实现drop目标对象.docx_第13页
第13页 / 共13页
亲,该文档总共13页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

实现drop目标对象.docx

《实现drop目标对象.docx》由会员分享,可在线阅读,更多相关《实现drop目标对象.docx(13页珍藏版)》请在冰点文库上搜索。

实现drop目标对象.docx

实现drop目标对象

第六部分:

实现Drop目标对象(OLEdrag&drop之旅)

欢迎你到OLE拖放操作的第六章!

这里将着重于一个实现了drop-target的小程序,这就意

味着我们的程序能够接收拖到它上面的对象(文件、图片、文本)了。

我们实现一个IDropTarget的COM接口允许OLE程序拖动数据到我们的程序上;这里仅仅

是一个简单的EDIT控件,所以他将CF_TEXT数据作为目标。

成为一个“DropTarget

为了时窗口可以接收拖放操作的数据,窗口必须注册为drop目标;有一个OLE的API调用

RegisterDragDrop来完成这个事情,函数的原型是:

WINOLEAPIRegisterDragDrop(HWNDhwnd,IDropTarget*pDropTarget);

第一个参数是窗口的HANDLE,这个窗口是拖动的目标窗口;第二个参数是一个指向

IDropTargetCOM对象的指针,COM/OLE运行时将在拖放操作的过程中调用这个方法。

同样有一个OLEAPI调用来将window从拖放操作中删除:

WINOLEAPIRevokeDragDrop(HWNDhwnd);

我们所要做的就是在窗口创建的时候调用

RegisterDragDrop,在窗口销毁的时候调用

RevokeDragDrop

在我们调用RegisterDragDrop之前,我们需要构造一个COM对象来支

不过我们前面已经介绍了。

IDropTarget

方法

描述

DragEnter

判断是否可以接受一个拖操作,以及接受之后的效果

DragOver

提供通过DoDragDrop函数执行的目标反馈

DragLeave

导致一个drop目标挂起它的返回行为

Drop

数据放进目标窗口

这些函数都由COM/OLE运行时在一个对象被拖到我们注册窗口的时候来调用。

就象上表显示的一样,每个函数都有不同的任务,我们需要做的就是实现这些函数。

实现IDropTarget

以我的经验,IDropTarget接口非常难以写为不涉及特定程序的代码,例如:

写成可以在所

有程序都使用的通用IDropTargetCOM对象是很难的。

这是因为IDropTarget要求在一个对象拖过你的目标窗口时显示图形效果,且也只有特定程

序代码才可以访问这些数据对象内容。

在我们的拖放接口之外,IDropTarget是最容易被集成到你窗口类的对象。

例如:

假定你已

经用C++类实现了一个自定义的窗口,为这个窗口添加一个多drop目标支持的最好方法就是

从IDropTarget直接继承,而不需要单独定义一个CDropTarget类;这意味着你的

drop-target代码能够访问所有你的窗口状态。

然而,我们这里提供完整的CDropTarget类:

classCDropTarget:

publicIDropTarget

{

public:

//IUnknownimplementation

HRESULT__stdcallQueryInteface(REFIIDiid,void**ppvObject);

ULONG__stdcallAddRef(void);

ULONG__stdcallRelease(void);

//IDropTargetimplementation

HRESULT__stdcallDragEnter(IDataObject*pDataObject,DWORgrfKeyState,POINTL

pt,DWORD*pdwEffect);

HRESULT__stdcallDragOver(DWORDgrfKeyState,POINTLpt,DWORD*pdwEffect);

HRESULT__stdcallDragLeave(void);

HRESULT__stdcallDrop(IDataObject*pDataObject,DWORDgrfKeyState,POINTLpt,

DWORD*pdwEffect);

//Constructor

CDropTarget(HWNDhwnd);

~CDropTarget();

private:

//internalhelperfunction

DWORDDropEffect(DWORDgrfKeyState,POINTLpt,DWORDdwAllowed);

boolQueryDataObject(IDataObject*pDataObject);

//Privatemembervariables

longm_lRefCount;

HWNDm_hWnd;

boolm_fAllowDrop;

//Otherinternalwindowmembers

};

除引用记数器外,我们需要存储另外两个变量:

m_hWnd变量是drop-target窗口的

HANDLE,这个在提供可见效果的时候需要;m_fAllowDrop用来指示被拖动的数据对象是否

包含我们需要的有用数据。

因此我们没有连续查询数据对象,这是一个最优的办法。

IDropTarget:

:

DragEnter方法

让我们首先看一下IDropTarget函数,因为这是在一个对象被拖过我们窗口时最先被COM

调用的函数:

HRESULTDragEnter(

IDataObject*pDataObject,

DWORDgrfKeyState,

POINTLpt,

DWORD*pdwEffect

);

仔细看一下上面函数的原型,因为这对于理解每个参数怎么样使用很重要:

IDataObject-

第一个参数是拖放操作的源对象通过

COM传递来的数据对象指针。

IDataObject

是拖放操作带来数据的传输媒体,我们在

DragEnter的时候查看数据对

象来看是否有我们想要的任何数据。

grfKeyState-保留键盘修饰符的状态,例如:

Control、Alt、和Shift以及鼠标按键的

状态。

是有一到多个MK_CONTROL、MK_SHIFT、MK_ALT、MK_BUTTON、

MK_LBUTTON等组成的简单DWORD变量

pt-一个POINTL结构体,包含了鼠标进入我们窗口的坐标;在许多程序中,这个参数

用来检查鼠标是否放置在允许的drop区域上,或者用来简单的放置某些插入光标来指示

drop数据放在那里。

pdwEffect-—个DWORD的指针,指岀drop源允许的drop效果。

这个值和DoDragDrop的dwOKEffect值相同。

我们的DragEnter实现需要做几个通常的工作,另外画一个图形的反馈:

1.检查提供的数据对象,然后判断它是否包含任何有用的数据

2.检查存储在grfKeyState的键盘状态,并且计算应该是什么样的drop效果,例如:

果Control键按下,drop效果应该是复制,如果Shift被按下,drop效果应该是移动。

3.验证这些效果是否与drop源的效果相兼容

4.存储最终的drop效果到pdwEffect的DWORD指针。

不要如此复杂吧!

DragEnter的目的就是简单的对拖放操作说"yes还是NO",指定采用

什么drop效果以便于OLE更新鼠标光标。

HRESULT_stdcallCDropTarget:

:

DragEnter(IDataObject*pDataObject,DWORDrfKeyState,

POINTLpt,DWORD*pdwEffect)

{

//doesthedataobjectcontaindatawewant?

m_fAllowDrop=QueryDataObject(grfKeyState,pdwEffect,pDataObject);

if(m_fAllowDrop)

//getthedropeffectbasedonkeyboardstate

*pdwEffect=DropEffect(grfKeyState,pt,*pdwEffect);

SetFocus(m_hWnd);

PositionCursor(m_hWnd,pt);

}

else

{

*pdwEffect=DROPEFFECT_NONE;

}

returnS_OK;

}

除了设置光标下的窗口和设置EDIT位置外,DragEnter的功能已经由两个内部协助函数代

理而简化了:

boolCDropTarget:

:

QueryDataObject(IDataObject*pDataObject)

{

FORMATETCfmtetc={CF_TEXT,0,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};

//doesthedataobjectsupportCF_TEXTusingaHGLOBAL?

returnpDataObject->QueryGetData(&fmtetc)==S_OK?

true:

false;

}

QueryDataObject是一个私有函数,纯粹用来检查提供的数据,然后决定它是否包含对我们

的drop目标有用的数据。

在我们的例子中,我们仅仅接受CF_TEXT数据存储为HGLOBAL,

因此这是我们请求的类型。

一个私有成员变量m_fAllowDrop用来记住这个决定。

DWORDCDropTarget:

:

DropEffect(DWORDgrfKeyState,POINTLpt,DWORDdwAllowed)

{

DWORDdwEffect=0;

//1.检查pt来看是否允许drop操作在某个位置

//2.计算岀基于grfKeyState的drop效果

if(grfKeyState&MK_CONTROL)

dwEffect=dwAllowed&DROPEFFECT_COPY;

elseif(grfKeyState&MK_SHIFT)

{

dwEffect=dwAllowed&DROPEFFECT_MOVE;

}

//3.非键盘修饰符指定(或drop效果不允许),因此基于drop源的效果

if(dwEffect==0)

{

if(dwAllowed&DROPEFFECT_COPY)dwEffect=DROPEFFECT_COPY;if(dwAllowed&DROPEFFECT_MOVE)dwEffect=DROPEFFECT_MOVE;

}

returndwEffect;

}

DropEffect协助函数用来计算基于键盘状态的drop效果,并且这个效果是达到源允许的。

首先grfKeyState变量用来检查看是否使用了Control或Shift键;这些键的标准的OLE行为是Control应该是复制数据,shift应该是移动数据。

如果两个都按下,数据应该是连接(例

如:

源应该建立一个到目标的快捷方式),但我们不支持这个功能。

主要的事情是使用位与操作符来对dwEffect赋drop效果值的时候:

dwEffect=dwAllowed&DROPEFFECT_COPY;

这个分配的结构很简单-dwEffect将拥有DROPEFFECT_COPY,但只有在dwAllowed变量中仅仅包含这个值的时候起作用;这种逻辑用法防止我们强制执行一个源不允许的drop效果。

下面是看一下在没有键盘修饰符的时候怎么做,例如:

Control和Shift没有使用。

在这种情

况我,我们检查拖放的源对象允许的drop效果,以及选择使用哪个效果;在我们的实现中,我

们是移动数据而不是复制。

使用图形返回效果来得到一个机会清理。

这个函数在拖放操作的整个生命周期中被多次调用,因此,高效的写这个函数很重要;

DragOver在键盘修饰符改变(shift/control等)或当鼠标移动的时候被调用。

告诉OLE采用

什么样基于键盘状态和鼠标位置的drop效果是这个函数的责任:

HRESULT__stdcallCDropTarget:

:

DragOver(DWORDgrfKeyState,POINTLpt,DWORD*

pdwEffect)

{

if(m_fAllowDrop)

{

*pdwEffect=DropEffect(grfKeyState,pt,*pdwEffect);

PositionCursor(m_hWnd,pt);

}

else

{

*pdwEffect=DROPEFFECT_NONE;

}

returnS_OK;

}

DragOver写的很简单,逻辑上与DragEnter相同,我们使用前面计算过的m_fAllowDrop

和DropEffect协助函数来通过pdwEffect指针返回drop效果。

IDropTarget:

:

DragLeave函数

这个函数在鼠标光标移到drop目标窗口外面的时候调用,或者按下Escape键来取消拖放操

作时。

它的原型如下:

HRESULT__stdcallCDropTarget:

:

DragLeave(void)

{

returnS_OK;

}

这是这个函数的基本写法;这个函数存在的唯一原因是便于程序在鼠标移到窗口外面的时候

例如:

想象下面的场景,无论什么东西都拖过目标对象,

DragEnter函数用来改变窗口边界的颜色;在这种情况下,DragLeave函数用来恢复窗口边界

的颜色。

IDropTarget:

:

Drop函数

Drop函数的原型与DragEnter函数相同:

HRESULT__stdcallCDropTarget:

:

Drop(IDataObject*pDataObject,DWORDgrfKeyState,

POINTLpt,DWORD*pdwEffect)

{

PositionCursor(m_hWnd,pt);

if(m_fAllowDrop)

{

DropData(m_hWnd,pDataObject);

*pdwEffect=DropEffect(grfKeyState,pt,*pdwEffect);

}

else

{

*pdwEffect=DROPEFFECT_NONE;

}

returnS_OK;

}

在OLE判断拖放操作到头的时候调用该函数,我们得到一个在DragEnter同样的

IDataObject的接口指针,我们可以从中得到数据并粘贴到我们的编辑窗口中。

DropData协助函数用来访问数据对象内部的CF_TEXT数据,并插入到edit控件中;这个程

序是是纯理论的,我们已经知道怎么样访问一个数据对象了,这里不在不厌其烦的介绍,你

可以看源代码。

postedon2006-03-0608:

51笨笨阅读(606)评论

(2)编辑收藏收藏至365Key所属

分类:

OLEDrag&Drop

评论:

#re:

第六部分:

实现Drop目标对象(OLEdrag&drop之旅)2006-05-2420:

11|王鴻杰

您好〜我是來自台灣的讀者,想要請教您,如果我想要寫一個ActiveX元件,嵌入IE中作為一個檔案拖放

的接受器,是否可行呢?

以我的經驗,我將程式寫在一般的桌面應用程式,是可以實現OLE拖放,可是嵌到網頁裡面以後,我將檔

案拖進IE當中,我的ActiveX元件卻沒有反應。

您是否有可以參考的ActiveX程序呢?

ps.我是使用BorlandC++Builder去開發ActiveControl和ActiveForm,結果都沒有用。

回复

#re:

第六部分:

实现Drop目标对象(OLEdrag&drop之旅)2006-05-2513:

19|笨笨

我没有相关的程序

我想你因看一下IE是如何处理DRAGOVER等事件的,我试验发现他已经是一个TARGET。

你的ACTIVEXcontrol有窗口吗?

回复

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2