duilib 子窗口位置_Duilib改进窗口拖动,使整个窗口都能拖动两种方法(转载)

知识回顾:

当鼠标在窗口内移动,点击或者释放时都会产生WM_NCHITTEST消息,响应函数OnNcHitTest会返回一个枚举值,系统会根据这个枚举值进行相应的处理。 当返回值为HTCAPTION时,系统会认为此时鼠标位于标题栏上,因而当鼠标按下并移动时就会执行拖动操作。我们需要做的就是响应这个消息,然后根据自己的需要,返回HTCAPTION参数即可!

所以Duilib在客户区设置标题栏能让用户拖动窗口,其实就是当鼠标按下时在OnNcHitTest消息响应里面返回HTCAPTION,让系统默认为此时鼠标位于标题栏,原理就这么简单。

这种方法不修改Duilib库的源码,需要的话直接在你自己的窗口类中添加两个方法实现,不需要的话,还使用原来的方法。

方法一:

MyWnd

.h文件

1 virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled);2

3 BOOL IsInStaticControl(CControlUI * pControl);

.cpp文件

加入头文件

1 #include

1 LRESULT MyWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled)2 {3 POINT pt;4 RECT rcClient;5 RECT rcCaption;6 CControlUI * pControl =NULL;7

8 rcCaption =m_PaintManager.GetCaptionRect();9 GetClientRect(m_PaintManager.GetPaintWindow(), &rcClient);10 pt.x =GET_X_LPARAM(lParam);11 pt.y =GET_Y_LPARAM(lParam);12 ::ScreenToClient(m_PaintManager.GetPaintWindow(), &pt);13

14 if (-1 == rcCaption.bottom) ///< xml中描述bottom为-1时,整个窗口区域都可以拖动15 {

16 rcCaption.bottom =rcClient.bottom;17 }18

19 if ((pt.x >=rcClient.left)20 && (pt.x =rcCaption.top)22 && (pt.y

31 return__super::OnNcHitTest(uMsg, wParam, lParam, bHandled);32 }33

34 BOOL MyWnd::IsInStaticControl(CControlUI *pControl)35 {36 CDuiString strClassName;37 std::vectorvctStaticName;38 std::vector::iterator it;39

40 if (NULL ==pControl)41 returnFALSE;42

43 strClassName = pControl->GetClassName();44 strClassName.MakeLower();45 vctStaticName.push_back(L"controlui");46 vctStaticName.push_back(L"textui");47 vctStaticName.push_back(L"labelui");48 vctStaticName.push_back(L"containerui");49 vctStaticName.push_back(L"horizontallayoutui");50 vctStaticName.push_back(L"verticallayoutui");51 vctStaticName.push_back(L"tablayoutui");52 vctStaticName.push_back(L"childlayoutui");53 vctStaticName.push_back(L"dialoglayoutui");54

//可以指定那些控件在响应 WM_NCHITTEST 消息 不返回 HTCAPTION

55 it =std::find(vctStaticName.begin(), vctStaticName.end(), strClassName);56 return (it !=vctStaticName.end());57 }

最后在窗口xml中指定caption="0,0,0,-1",不管窗口大小如何变,都可以整个窗口拖动啦~

效果图:

方法二:

这种方法是纯Win32的函数调用,首先我们要理清楚拖动窗口任意位置移动的原理:

其实在移动过程中会产生WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUP这三个消息,其过程就是鼠标左键按下---->拖动窗口移动--->鼠标左键弹起   窗口移动完成。因此我们可以在自己的窗口处理函数中对这三个消息进行处理。

首先在.h文件中定义三个窗口的成员变量以及三个消息函数响应的声明:

private:

Crect m_startRect;//窗口的初始位置所在的矩形

bool m_isMouseDown; //鼠标是否按下 初始化为false

CPoint m_startPoint;//鼠标按下的位置

................public:

LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled);

LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled);

LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled);

..............

.cpp中进行响应的处理

LRESULT CxxxWnd::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled)

{

isMouseDown= true;//记录鼠标按下//鼠标按下时的坐标

m_startPoint.x =GET_X_LPARAM(lParam);

m_startPoint.y=GET_Y_LPARAM(lParam);//鼠标按下时窗口的位置

GetWindowRect(this->GetHWND(),&startRect);return 0;

}

LRESULT CLoginWnd::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled)

{if(isMouseDown == true)

{

POINT point;//获取当前鼠标的位置//第一种获取位置方法//point.x = GET_X_LPARAM(lParam);//point.y = GET_Y_LPARAM(lParam);//第二种获取位置方法

::GetCursorPos(&point);

::ScreenToClient(m_PaintManager.GetPaintWindow(),&point);int Dx = point.x -startPoint.x;int Dy = point.y -startPoint.y;

startRect.left+=Dx;

startRect.right+=Dx;

startRect.top+=Dy;

startRect.bottom+=Dy; //获取新的位置

SetWindowPos(this->GetHWND(),NULL,startRect.left,startRect.top,0,0,SWP_NOSIZE); //将窗口移到新的位置

}return 0;

}

LRESULT CLoginWnd::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled)

{//左键弹起,改变鼠标状态

isMouseDown = false;return 0;

}

运行效果:

可惜这样修改后有一个bug,当你拖动窗口一直到任务栏,然后松开鼠标左键,这时窗口自动跟着鼠标移动,暂时没找到这个bug,所以暂时采用响应WM_NCHITTEST消息方式,

在消息响应函数里面直接返回 HTCAPTION

1 LRESULT CLoginWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled)2 {3 returnHTCAPTION;4 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值