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

要实现的效果:

        鼠标点击控件(自绘控件,可继承任意控件类,下文将给出示例),并且进行拖拽,会有一个半透明黑色阴影来表示当前拖动的位置。当松开鼠标,控件重新绘制在鼠标松开的位置。拖拽功能的实现代码主要在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(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(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);
	}
}



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

教你如何用duilib实现控件可拖动,可拖拽_第1张图片拖动过程的黑色透明阴影


教你如何用duilib实现控件可拖动,可拖拽_第2张图片松开鼠标后,重新绘制位置



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

你可能感兴趣的:(duilib,实战,自定义控件,duilib可拖动,duilib可拖拽)