要实现的效果:
鼠标点击控件(自绘控件,可继承任意控件类,下文将给出示例),并且进行拖拽,会有一个半透明黑色阴影来表示当前拖动的位置。当松开鼠标,控件重新绘制在鼠标松开的位置。拖拽功能的实现代码主要在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);
}
}
可拖动控件完成了,我们看下效果吧:
拖动过程的黑色透明阴影
松开鼠标后,重新绘制位置
至此,可拖动自定义控件完成了,这是项目功能所需写的代码,希望能帮助到需要的人,欢迎大家提意见!