上一次我们实现了让窗口支持DropTarget,我们实现了一个叫做IDropTarget的接口。但是还没有给控件实现,当然如果你在这个窗口里面只有一个控件实现DropTarget的话,你完全可以使用Rect来进行区域限制,但是这样还是比较麻烦,还要手动添加一堆代码。所以我们直接让控件实现这个功能,只需要一个bool属性,就可以控制一个控件是否能接受拖拽。

为了减少源代码的修改,我们弄下面这样一个接口,让CPaintManagerUI去实现。

class IDuiDropTarget
{
public:virtual  HRESULT OnDragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL ptl,  DWORD *pdwEffect) = 0;virtual HRESULT  OnDragOver(DWORD grfKeyState, POINTL pt,DWORD *pdwEffect) = 0;virtual HRESULT  OnDragLeave() = 0;virtual HRESULT  OnDrop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) = 0;
};

其实我们完全可以让CPaintManagerUI直接去继承IDropTarget,但是这样做代码会比较乱,CPaintManagerUI里面的代码会增添很多,所以我们还是把多余的代码扔到我们自己实现的CDropTargetEx里面去吧。

我们在CDropTargetEx里面增加一个IDuiDropTarget* m_pDuiDropTarget;成员,用来操作CPaintManagerUI的对象。在调用bool DragDropRegister(IDuiDropTarget* pDuiDropTarget,HWND hWnd,DWORD AcceptKeyState=MK_LBUTTON);函数时,把CPaintManagerUI的指针传入。然后在CDropTargetEx的实现里面去回调IDuiDropTarget的函数。

class CDropTargetEx : public IDropTarget
{
public:CDropTargetEx(void);bool DragDropRegister(IDuiDropTarget* pDuiDropTarget,HWND hWnd,DWORD AcceptKeyState=MK_LBUTTON);bool DragDropRevoke(HWND hWnd);HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, __RPC__deref_out void **ppvObject);ULONG STDMETHODCALLTYPE AddRef();ULONG STDMETHODCALLTYPE Release();//进入HRESULT STDMETHODCALLTYPE DragEnter(__RPC__in_opt IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect);//移动HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect);//离开HRESULT STDMETHODCALLTYPE DragLeave();//释放HRESULT STDMETHODCALLTYPE Drop(__RPC__in_opt IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect);private:~CDropTargetEx(void);HWND m_hWnd;IDropTargetHelper* m_piDropHelper;bool m_bUseDnDHelper;IDuiDropTarget* m_pDuiDropTarget;DWORD m_dAcceptKeyState;ULONG  m_lRefCount;
};///CDropTargetEx::CDropTargetEx(void){m_lRefCount = 1;// Create an instance of the shell DnD helper object.if ( SUCCEEDED( CoCreateInstance ( CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,IID_IDropTargetHelper, (void**) &m_piDropHelper ) )){m_bUseDnDHelper = true;}}CDropTargetEx::~CDropTargetEx(void){if (m_piDropHelper){m_piDropHelper->Release();}m_bUseDnDHelper = false;m_lRefCount = 0;}bool CDropTargetEx::DragDropRegister(IDuiDropTarget* pDuiDropTarget,HWND hWnd,DWORD AcceptKeyState){if(!IsWindow(hWnd))return false;m_pDuiDropTarget = pDuiDropTarget;HRESULT s = ::RegisterDragDrop (hWnd,this);m_hWnd = hWnd;if(SUCCEEDED(s)){m_dAcceptKeyState = AcceptKeyState;return true;}else { return false; }}bool CDropTargetEx::DragDropRevoke(HWND hWnd){if(!IsWindow(hWnd))return false;HRESULT s = ::RevokeDragDrop(hWnd);return SUCCEEDED(s);}HRESULT STDMETHODCALLTYPE CDropTargetEx::QueryInterface(REFIID riid, __RPC__deref_out void **ppvObject){static const QITAB qit[] ={QITABENT(CDropTargetEx, IDropTarget),{ 0 }};return QISearch(this, qit, riid, ppvObject);}ULONG STDMETHODCALLTYPE CDropTargetEx::AddRef(){return InterlockedIncrement(&m_lRefCount);}ULONG STDMETHODCALLTYPE CDropTargetEx::Release(){ULONG lRef = InterlockedDecrement(&m_lRefCount);if (0 == lRef){delete this;}return m_lRefCount;}//进入HRESULT STDMETHODCALLTYPE CDropTargetEx::DragEnter(__RPC__in_opt IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect){if ( m_bUseDnDHelper ){m_piDropHelper->DragEnter (m_hWnd, pDataObj, (LPPOINT)&pt, *pdwEffect );}return m_pDuiDropTarget->OnDragEnter(pDataObj,grfKeyState,pt,pdwEffect);}//移动HRESULT STDMETHODCALLTYPE CDropTargetEx::DragOver(DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect){if ( m_bUseDnDHelper ){m_piDropHelper->DragOver((LPPOINT)&pt, *pdwEffect);}return m_pDuiDropTarget->OnDragOver(grfKeyState,pt,pdwEffect);}//离开HRESULT STDMETHODCALLTYPE CDropTargetEx::DragLeave(){if ( m_bUseDnDHelper ){m_piDropHelper->DragLeave();}return m_pDuiDropTarget->OnDragLeave();}//释放HRESULT STDMETHODCALLTYPE CDropTargetEx::Drop(__RPC__in_opt IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, __RPC__inout DWORD *pdwEffect){m_piDropHelper->Drop ( pDataObj,  (LPPOINT)&pt, *pdwEffect );return m_pDuiDropTarget->OnDrop(pDataObj,grfKeyState,pt,pdwEffect);}

这样就相当于CPaintManagerUI间接地实现了IDropTarget接口。我们下一步的任务就是,把CPaintManagerUI捕获到的拖拽事件“路由”给CControlUI。

为了让CControlUI支持这个事件,我们先给它添加下面几个成员函数。

//拖拽相关virtual void  OnDragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINT pt,  DWORD *pdwEffect);virtual void  OnDragOver(DWORD grfKeyState, POINT pt,DWORD *pdwEffect);virtual void  OnDragLeave();virtual void  OnDrop(IDataObject *pDataObj, DWORD grfKeyState, POINT pt, DWORD *pdwEffect);

注意,这里面是虚函数,这样写更灵活,因为CControlUI的派生类很多,方便以后重写。

同样地,我们在给CControlUI加一个bool  m_bDragEnabled;属性,并在SetAttribute里面加入如下的代码

 else if( _tcscmp(pstrName, _T("droptarget")) == 0 ) SetDropEnabled(_tcscmp(pstrValue, _T("true")) == 0);

以便在xml里面开启和禁止这个功能。

如何让控件里面新加入的这几个函数响应,就需要在CPaintManagerUI里面做手脚了。这一点也是DUI技术的核心,把窗口的事件过滤到控件,在我们操作控件时仿佛像直接操作一个窗口一样。这一点我们可以效仿一下,ButtonDown ,ButtonUp和MouseMove的处理。

1.首先,做第一个模仿,给CPaintManagerUI加一个CControlUI* m_pEventDrop;变量,这个表示当前接收DropTarget的控件,
2.在HRESULT  OnDragOver(DWORD grfKeyState, POINTL pt,DWORD *pdwEffect);事件并没有传递IDataObject *pDataObj,在CControlUI响应virtual void  OnDragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINT pt,  DWORD *pdwEffect);时,恰好是OnDragOver路由过来的。所以我们要保存这个IDataObject *pDataObj对象,所以在CPaintManagerUI里面还要加一个 IDataObject*       m_pCurDataObject;变量。

3.下面是关键,我们看一个事件是如何从窗口过滤到 控件

HRESULT CPaintManagerUI::OnDragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL ptl,  DWORD *pdwEffect)
{m_pCurDataObject = pDataObj;POINT pt={ptl.x,ptl.y};::ScreenToClient(m_hWndPaint,&pt);CControlUI* pHover = FindControl(pt);if( pHover == NULL ) {*pdwEffect = DROPEFFECT_NONE;return S_OK;}// Generate mouse hover eventpHover->OnDragEnter(pDataObj,grfKeyState,pt,pdwEffect);m_pEventDrop = pHover;return   S_OK;}HRESULT  CPaintManagerUI::OnDragOver(DWORD grfKeyState, POINTL ptl,DWORD *pdwEffect)
{POINT pt={ptl.x,ptl.y};::ScreenToClient(m_hWndPaint,&pt);m_ptLastMousePos = pt;CControlUI* pNewHover = FindControl(pt);if(pNewHover==NULL){*pdwEffect = DROPEFFECT_NONE;return S_OK;}if( pNewHover != NULL && pNewHover->GetManager() != this ){*pdwEffect = DROPEFFECT_NONE;return S_OK;}if( pNewHover != m_pEventDrop && m_pEventDrop != NULL ) {m_pEventDrop->OnDragLeave();m_pEventDrop = NULL;}if( pNewHover != m_pEventDrop && pNewHover != NULL ) {pNewHover->OnDragEnter(m_pCurDataObject,grfKeyState,pt,pdwEffect);m_pEventDrop = pNewHover;}if( pNewHover != NULL ) {pNewHover->OnDragOver(grfKeyState,pt,pdwEffect);}return S_OK;
}HRESULT  CPaintManagerUI::OnDragLeave()
{m_pCurDataObject = NULL;if( m_pEventDrop != NULL ) {m_pEventDrop->OnDragLeave();m_pEventDrop = NULL;}return S_OK;
}HRESULT  CPaintManagerUI::OnDrop(__RPC__in_opt IDataObject *pDataObj, DWORD grfKeyState, POINTL ptl, __RPC__inout DWORD *pdwEffect)
{POINT pt={ptl.x,ptl.y};::ScreenToClient(m_hWndPaint,&pt);if( m_pEventDrop != NULL ) {m_pEventDrop->OnDrop(pDataObj,grfKeyState,pt,pdwEffect);}else{*pdwEffect = DROPEFFECT_NONE;return S_OK;}return S_OK;
}

这些代码,是我照搬的ButtonDown ,ButtonUp和MouseMove的处理。大家可以在MessageHanler里面看一下,因为这个事件和鼠标的事件太相似了。

最后,在控件响应时,如果控件没有开启droptarget属性的话,就让父控件去响应,这一点也是模仿的鼠标事件,如果当前控件mouse属性为false的话,则去调用父控件的mouse消息。

void  CControlUI::OnDragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINT pt,  DWORD *pdwEffect)
{if (IsDropEnabled()){*pdwEffect = DROPEFFECT_COPY;}else{*pdwEffect = DROPEFFECT_NONE;if( m_pParent != NULL )m_pParent->OnDragEnter(pDataObj,grfKeyState,pt,pdwEffect);}
}void  CControlUI::OnDragOver(DWORD grfKeyState, POINT pt,DWORD *pdwEffect)
{if (IsDropEnabled()){*pdwEffect = DROPEFFECT_COPY;}else{*pdwEffect = DROPEFFECT_NONE;if( m_pParent != NULL )m_pParent->OnDragOver(grfKeyState,pt,pdwEffect);}
}void  CControlUI::OnDragLeave()
{if (IsDropEnabled())elseif( m_pParent != NULL )m_pParent->OnDragLeave();}void  CControlUI::OnDrop(IDataObject *pDataObj, DWORD grfKeyState, POINT pt, DWORD *pdwEffect)
{if (IsDropEnabled()){*pdwEffect = DROPEFFECT_COPY;}else{*pdwEffect = DROPEFFECT_NONE;if( m_pParent != NULL )m_pParent->OnDrop(pDataObj,grfKeyState,pt,pdwEffect);}}

到这里源码修改基本就完成了,我们现在可以测试一下,给一个控件指定droptarget = “true”属性。

这里我们看到了,在指定droptarget = “true”的控件上出现了,可拖放的图标。

在没有指定这个属性的控件上则是禁止状态

今天先介绍到这里了,有问题的话QQ联系我(Skilla:848861075)

关于Duilib的扩展——“拖放”实现(二)相关推荐

  1. spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入...

    <spring扩展点之二:spring中关于bean初始化.销毁等使用汇总,ApplicationContextAware将ApplicationContext注入> <spring ...

  2. Thingworx自定义扩展开发(二)- Widget Demo Coding

    系列 Thingworx自定义扩展开发(一)- 开发环境搭建.Extension Demo Coding Thingworx自定义扩展开发(二)- Widget Demo Coding Thingwo ...

  3. 黑马程序员全套Java教程_Java基础教程_异常(含扩展)(二十三)

    黑马程序员全套Java教程_Java基础教程_异常(含扩展)(二十三) 1.1 异常概述与异常体系结构 1.2 JVM遇到异常时的默认处理方案 1.3 异常处理 1.4 异常处理之try--catch ...

  4. 扩展log4j系列[二]为DailyRollingFileAppender加上maxBackupIndex属性

    在log4j的大多数appender中,都有maxBackupIndex属性,但是这个DailyRollingFileAppender没有,也就是说它会每天滚一个文件,却没有办法控制文件总个数.这绝对 ...

  5. 那些实用的 Chrome 扩展神器(二)

    之前已经写过 那些实用的 Chrome 扩展神器 ,如果你不能上谷歌没法直接安装Chrome扩展,可以使用https://crxdl.com/ 这个网站下载crx文件,然后手动安装.下面继续推荐几个实 ...

  6. Laravel5中通过SimpleQrCode扩展包生成二维码实例

    简介 Simple QrCode 是基于强大的Bacon/BaconQrCode库开发的适用于当前最流行的Laravel框架的一个扩展库.便于Laravel用户可以很方便地使用. 翻译 我们在寻找可以 ...

  7. 【nano系列】jetson nano 迁移系统、制作SD卡启动扩展内存(二)

    本文继上文刷机到EMMC内存后,为扩展内存空间,迁移系统到Micro SD卡并制作SD卡启动 我的SD卡在nano中显示的名称为 /dev/sda1 ,不同于其他文章 的 /dev/mmcblk1p1 ...

  8. php 扩展库curl下载,PHP添加CURL扩展库的二种方法

    说明: 本次编译只是单独编译php的扩展库,然后将编译好的php扩展库加到现在运行的php中,不对现在运行的php重新编译,对现在运行的php没有任何影响. 有两种方法可以实现这一操作,下面分别介绍. ...

  9. 基于Chrome的扩展开发(二)

    Chrome启动时默认的效果如下图所示,有"most visited","Searches","Recent bookmarks",&quo ...

最新文章

  1. 汇总 | OpenCV4中的非典型深度学习模型
  2. app 404 html,静态页面错误404(Flask框架)
  3. java配置常量_Java构建时间常量配置
  4. 第三周课程总结及实验报告(一)
  5. 52条SQL语句性能优化策略
  6. 树莓派智能家居-语音聊天机器人实现
  7. 仿QQ锁屏界面消息提示
  8. Angular Js 判断对象不为空对象的三种方法
  9. oracle 天转换成月函数_oracle中to_date详细用法示例(oracle日期格式转换)
  10. 洛谷——P1597 语句解析(两种解法)
  11. 登录获取token,token参数关联至所有请求的请求体内
  12. 44. Element insertBefore() 方法
  13. 游戏UI-头像框制作
  14. clickhouse索引原理介绍
  15. 在iOS7中修改键盘Return键的类型
  16. linux下如何查看hdmi设备,如何在Linux中设置HDMI数字播放 | MOS86
  17. java char定义为空_java – 检查char是否为空
  18. printf()中%n格式说明符
  19. 自然语言处理面试 | (1)胡盼盼(NLP入门到实践)总结
  20. N1 小钢炮docker安装迅雷方法

热门文章

  1. ARM-Linux嵌入式系统启动流程
  2. GPS卫星同步时钟(GPS授时服务器)在校园网络里的应用
  3. 大学计算机考试打字不及格,法考没过的人给你的忠告,2021年法考生必看
  4. 电子货架标签——系统结构
  5. 米大师服务端接入坑记录
  6. ADODB.Connection对象的Execute方法
  7. 【笑小枫的SpringBoot系列】【十五】SpringBoot根据模板生成Word
  8. css加号图标_一步步打造自己的纯CSS单标签图标库
  9. cad缩小了怎么还原,CAD怎么缩小图形,我来告诉你!
  10. numpy Week2.2