教你如何用duilib实现控件可拖动,可拖拽

来源:互联网 发布:win10 软件管家 编辑:程序博客网 时间:2024/06/06 02:14

要实现的效果:

        鼠标点击控件(自绘控件,可继承任意控件类,下文将给出示例),并且进行拖拽,会有一个半透明黑色阴影来表示当前拖动的位置。当松开鼠标,控件重新绘制在鼠标松开的位置。拖拽功能的实现代码主要在DoEvent函数和DoPostPaint函数中完成的。


实现步骤:

     1、 继承需要的控件并重写DoEvent函数,在UIEVENT_BUTTONDOWN、UIEVENT_BUTTONUP、UIEVENT_MOUSEMOVE三个事件

     2、在UIEVENT_BUTTONDOWN事件里调用AddPostPaint函数注册本控件

     3、在UIEVENT_MOUSEMOVE事件里计算新的控件位置,并且将新旧位置组合起来调用Invalidate函数刷新位置(否则会有残影)

    4、在UIEVENT_BUTTONUP事件里调用RemovePostPaint反注册自己,并且刷新控件。


    5、重写DoPostPaint函数完成阴影的绘制


自定义控件类的实现如下(类名可自行定义):

       CNetDevice类头文件.h实现如下:

#pragma once#include "../duilib/UIlib.h"using namespace DuiLib;class CNetDevice : public CContainerUI      //这里继承了CContainerUI,你也可以继承任意控件类如CButtonUI等,实现自定义控件{public:CNetDevice();~CNetDevice();LPVOID GetInterface(LPCTSTR pstrName);void DoEvent(TEventUI& event);void DoPostPaint(HDC hDC, const RECT& rcPaint);//CControlUI* CreateControl(LPCTSTR pstrClass);private:UINT m_uButtonState;POINT m_ptLastMouse;RECT m_rcNewPos;//CPaintManagerUI m_PaintManager;};



        CNetDevice类.cpp实现代码如下:

#include "stdafx.h"#include "NetDevice.h"CNetDevice::CNetDevice(){}CNetDevice::~CNetDevice(){}LPVOID CNetDevice::GetInterface(LPCTSTR pstrName){if (_tcscmp(pstrName, _T("NetDeviceInfo")) == 0){return static_cast<CNetDevice*>(this);}else{return CContainerUI::GetInterface(pstrName);}}void CNetDevice::DoEvent(TEventUI& event){if (event.Type == UIEVENT_BUTTONDOWN && IsEnabled()){if (::PtInRect(&m_rcItem, event.ptMouse)){m_uButtonState |= UISTATE_CAPTURED;m_ptLastMouse = event.ptMouse;m_rcNewPos = m_rcItem;if (m_pManager)m_pManager->AddPostPaint(this);return;}}else if (event.Type == UIEVENT_BUTTONUP){if ((m_uButtonState & UISTATE_CAPTURED) != 0){m_uButtonState &= ~UISTATE_CAPTURED;this->SetPos(m_rcNewPos);                   //这句是拖拽到目的地的关机,否则无法拖动到目的位置if (m_pManager){m_pManager->RemovePostPaint(this);m_pManager->Invalidate(m_rcNewPos);}NeedParentUpdate();return;}}else if (event.Type == UIEVENT_MOUSEMOVE){if ((m_uButtonState & UISTATE_CAPTURED) != 0){LONG cx = event.ptMouse.x - m_ptLastMouse.x;LONG cy = event.ptMouse.y - m_ptLastMouse.y;m_ptLastMouse = event.ptMouse;RECT rcCurPos = m_rcNewPos;rcCurPos.left += cx;rcCurPos.right += cx;rcCurPos.top += cy;rcCurPos.bottom += cy;//将当前拖拽块的位置 和 当前拖拽块的前一时刻的位置,刷新  CDuiRect rcInvalidate = m_rcNewPos;m_rcNewPos = rcCurPos;rcInvalidate.Join(m_rcNewPos);if (m_pManager) m_pManager->Invalidate(rcInvalidate);return;}}if (event.Type == UIEVENT_SETCURSOR){if (IsEnabled()){::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND)));return;}}CContainerUI::DoEvent(event);}void CNetDevice::DoPostPaint(HDC hDC, const RECT& rcPaint){if ((m_uButtonState & UISTATE_CAPTURED) != 0) {CDuiRect rcParent = m_pParent->GetPos();RECT rcUpdate = { 0 };rcUpdate.left = m_rcNewPos.left < rcParent.left ? rcParent.left : m_rcNewPos.left;rcUpdate.top = m_rcNewPos.top < rcParent.top ? rcParent.top : m_rcNewPos.top;rcUpdate.right = m_rcNewPos.right > rcParent.right ? rcParent.right : m_rcNewPos.right;rcUpdate.bottom = m_rcNewPos.bottom > rcParent.bottom ? rcParent.bottom : m_rcNewPos.bottom;CRenderEngine::DrawColor(hDC, rcUpdate, 0xAA000000);}}


在主对话框DuiFrameWnd.cpp中的InitWindow()函数中加入动态创建的自定义控件代码如下:

CVerticalLayoutUI* pVLNet = static_cast<CVerticalLayoutUI*>(m_PaintManager.FindControl(_T("vlSchoolNet")));//需要绘制的背景布局if (NULL != pVLNet){int _left = 205;int _top = 47;CNetDevice *pCNetDevice = new CNetDevice();//创建自定义控件if (NULL != pCNetDevice){pCNetDevice->SetFloat();                     //一定要设置为绝对定位,否则不能拖动SIZE leftTop = { _left,_top };pCNetDevice->SetFixedXY(leftTop);           // 自定义控件在背景布局的起始位置pCNetDevice->SetFixedWidth(80);pCNetDevice->SetFixedHeight(80);pCNetDevice->SetAttribute(_T("bkimage"), _T("file='SchoolNet/logo2.png' dest='16,0,64,57'"));CLabelUI *pUserNameLabel = new CLabelUI;     //自定义控件增加一个标签if (pUserNameLabel != NULL){pUserNameLabel->SetAttribute(_T("float"), _T("true"));pUserNameLabel->SetAttribute(_T("pos"), _T("8,60,46,80"));//pUserNameLabel->SetAttribute(_T("bkimage"), _T("SchoolNet/123.png"));pUserNameLabel->SetText(_T("大灰狼"));pUserNameLabel->SetAttribute(_T("textcolor"), _T("#FF9FFF99"));//pUserNameLabel->SetMouseEnabled(false);pCNetDevice->Add(pUserNameLabel);}pVLNet->Add(pCNetDevice);}}



可拖动控件完成了,我们看下效果吧:

拖动过程的黑色透明阴影


松开鼠标后,重新绘制位置



至此,可拖动自定义控件完成了,这是项目功能所需写的代码,希望能帮助到需要的人,欢迎大家提意见!