分享
 
 
 

实现自定义拖放---创建COleDropSource 对象来控制放置

王朝other·作者佚名  2006-02-01
窄屏简体版  字體: |||超大  

实现自定义拖放

实现自定义拖放

------创建COleDropSource

对象来控制放置

对于大多数应用程序,拖放功能的默认实现就已经足够了。但是,某些应用程序可能要求更改此标准行为。马上你会看到一个更改标准的拖放行为的例子,可以说明其实这是一件多么简单的事情,或许,你会得到一些自定义拖放的感性认识。

在我的工具条上,有一个按钮,资源ID号为:ID_DRAG_MY_OBJ,点击该按钮后,将开始拖放动作(注意,点击该按钮后已经了鼠标LButtonDown和LButtonUp两个动作,而不是按住鼠标左键不放),当鼠标在接受拖放的View中移动Move时,显示状态为拖放中,当在接受拖放的View中按下鼠标左键时,进行放置(Drop),被拖放的数据在该处放置。

这是一个不同于标准拖放的操作,该怎么完成这些动作呢?我们还是先来准备好需要的函数,一步一步从熟悉的默认拖放转变为自定义拖放。

首先,需要响应该按钮的函数,我把它放在CMainFrame中,于是CMainFrame.cpp就会增加一个函数OnDragMyObj()和一条消息映射ON_COMMAND(ID_DRAG_MY_OBJ, OnDragMyObj):

BEGIN_MESSAGE_MAP(CMainFrame,

uiFoldTabFrame)

ON_COMMAND(ID_DRAG_MY_OBJ,

OnDragMyObj)

END_MESSAGE_MAP()

void CMainFrame:: OnDragMyObj ()

{

//具体的实现将在后面逐渐清晰。

}

在MFC框架下,一个普通的拖放事怎么完成的?目的端,在接收拖放的窗体类中放置一个COleDropTarget对象,通过RegisterDragDrop

API来注册,实现该COleDropTarget的DragEnter、DragOvert、DragLeave、Drop等方法来处理接收窗体中不同鼠标状态下的拖动或放置,在窗体不需要再接收任何拖动过来的数据时使用RevokeDragDrop来解除注册。源端,生成一个COleDataSource 对象,调用该COleDataSource对象的DoDragDrop 方法开始拖放动作。这样就开始了一个拖放,我们还可以以一个RichEdit为例,来说明通常的拖放行为,请大家辛苦一点看下面这段英文:

1.

When

the mouse moves over a selected area of text it's cursor shape changes to an

arrow.

2.

When

the left button is pressed, the selection is not removed. Instead an internal

state is set to indicate that a drag-drop operation might be about to start.

3.

When

the mouse is first moved (and the internal state indicates that the left button

is currently being held down inside a selected area of text), the drag and drop

operation starts.

4.

At

this point, OLE takes over and handles all further mouse messages until the

operation is complete.

5.

However,

if the left button is released and the mouse didn't move at all, it is customary

for the RichEdit's selection to be cleared and the text-caret positioned under

the mouse.

接下来,我们来看看对于我们期望实现的例子,按照拖放一般做法有没有问题,如果有问题,问题在哪里?

为了准备被传送的数据,我们实现了一个简单的StringToHandle函数。这个函数的作用就是将一个普通的 char* string 转化为

HGLOBAL 的形式,这样才能在OLE 中使用它。

HANDLE StringToHandle(char *szText, int

nTextLen)

{

void

*ptr;

// if text length is -1 then treat as a nul-terminated string

if(nTextLen == -1)

nTextLen = lstrlen(szText) + 1;

// allocate and lock a global memory buffer. Make it fixed

// data so we don't have to use GlobalLock

ptr = (void *)GlobalAlloc(GMEM_FIXED, nTextLen);

// copy the string into the buffer

memcpy(ptr, szText, nTextLen);

return ptr;

}

然后,我们来修改上面所述OnDragMyObj函数:

void CMainFrame:: OnDragMyObj ()

{

HGLOBAL hData = StringToHandle("Hello,

World", -1);

if (hData != NULL)

{

COleDataSource ds;

ds.CacheGlobalData(CF_TEXT, hData);

DROPEFFECT de = ds.DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE);

}

}

只需再去实现接收拖放窗体的DragEnter、DragOvert、DragLeave、Drop等方法,这些方法的实现我在这里就不深入讲解了,因为你在任何有关拖放的资料上都可以查到这几个函数的实现例子。好了,应该说关于拖放的代码已经完成了,但是它能正确工作吗?不能,至少不是按照我们的要求工作。

为了弄清楚问题出在哪里,其实COleDataSource是个大管家,它通过DoDragDrop来发出司令,DoDragDrop其实就是大管家手里的工作流程图,我们来看看COleDataSource::DoDragDrop的参数:

DROPEFFECT DoDragDrop(

DWORD

dwEffects = DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK,

LPCRECT

lpRectStartDrag = NULL,

COleDropSource*

pDropSource = NULL

);

来看第三个参数pDropSource,用于指定相应的drop

source,这个drop

source就是COleDataSource手下的一个小工,将在DoDragDrop中被安排来做一些杂事.

如果pDropSource为NULL,

COleDropSource

会作为默认的drop

source . 这正好是我们在上面代码中使用的情况,也就是说,大管家事先就有个人选COleDropSource, 如果找不到临时的小工,COleDropSource将会为我们做一些他会做的事情。

那,COleDropSource又是如何帮我们做事呢?这就要归功于QueryContinueDrag函数,我作了一点简化,剔出了不必要解释的变量。

SCODE COleDropSource::QueryContinueDrag(BOOL

bEscapePressed, DWORD dwKeyState)

{

ASSERT_VALID(this);

// 检查是否按下Esc键或者是否按下鼠标右键 – 如果是,取消拖放

if (bEscapePressed || (dwKeyState & MK_RBUTTON) != 0)

{

m_bDragStarted = FALSE; // avoid unecessary cursor setting

return DRAGDROP_S_CANCEL;

}

//

检查鼠标左键是否处于弹起状态,如果是,就结束拖放,并执行放置动作

if ((dwKeyState

& MK_LBUTTON) == 0)

return m_bDragStarted ? DRAGDROP_S_DROP : DRAGDROP_S_CANCEL;

// 否则,继续由OLE监控鼠标状态…

return S_OK;

}

但是,为什么会出差错,COleDropSource做的事并不是我们想要的结果呢?原因在于COleDropSource其实是个脑袋不开窍的机器人,它做任何事情都一样,只是按照它会做的方式做,当鼠标左键按下时开始拖放,当鼠标左键弹起时结束拖放,并告诉大管家该进行放置了,而大管家在工作流程DoDragDrop中就会把这个命令传给下一个处理者COleDropTarget。

怎么办?既然COleDropSource脑袋不开窍,我们就只好自己给大管家出个小工,这个小工其实是和COleDropSource差不多的另外一个机器人,只是他知道按照我们的要求根据拖放中鼠标的状态来进行处理。

这个机器人就是CMyOleDropSource,

class

CMyOleDropSource : public COleDropSource

{

public:

CMyOleDropSource();

virtual ~CMyOleDropSource();

virtual SCODE QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState);

};

uiOleDropSource::uiOleDropSource()

{

}

uiOleDropSource::~uiOleDropSource()

{

}

SCODE

CMyOleDropSource ::QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState)

{

ASSERT_VALID(this);

//检查是否按下Esc键或者是否按下鼠标右键 – 如果是,取消拖放

if (bEscapePressed || (dwKeyState & MK_RBUTTON) != 0)

{

m_bDragStarted = FALSE; // avoid unecessary cursor setting

return DRAGDROP_S_CANCEL;

}

//检查鼠标左键是否被按下,如果是,就结束拖放,并执行放置动作

if ((dwKeyState & MK_LBUTTON)

!= 0)

return m_bDragStarted ? DRAGDROP_S_DROP : DRAGDROP_S_CANCEL;

//否则,继续由OLE监控鼠标状态…

return S_OK;

}

我们再对OnDragMyObj作下面的修改,就大功告成了。

void CMainFrame:: OnDragMyObj ()

{

HGLOBAL hData = StringToHandle("Hello,

World", -1);

if (hData != NULL)

{

COleDataSource ds;

ds.CacheGlobalData(CF_TEXT, hData);

CMyOleDropSource

dropSource;

DROPEFFECT de = ds.DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE,0,&dropSource);

}

}

现在,你去实验,一定能够满足我们需要实现例子的要求。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有