转载:http://www.cnblogs.com/XiHua/articles/3490490.html
转载:http://blog.csdn.net/lostspeed/article/details/19275249
知识回顾:
当鼠标在窗口内移动,点击或者释放时都会产生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 <algorithm>
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 < rcClient.right) 21 && (pt.y >= rcCaption.top) 22 && (pt.y < rcCaption.bottom)) 23 { 24 pControl = m_PaintManager.FindControl(pt); 25 if (IsInStaticControl(pControl)) 26 { 27 return HTCAPTION; 28 } 29 } 30 31 return __super::OnNcHitTest(uMsg, wParam, lParam, bHandled); 32 } 33 34 BOOL MyWnd::IsInStaticControl(CControlUI * pControl) 35 { 36 CDuiString strClassName; 37 std::vector<CDuiString> vctStaticName; 38 std::vector<CDuiString>::iterator it; 39 40 if (NULL == pControl) 41 return FALSE; 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; }
运行效果:
参考:http://blog.csdn.net/luanwujian/article/details/9059861
可惜这样修改后有一个bug,当你拖动窗口一直到任务栏,然后松开鼠标左键,这时窗口自动跟着鼠标移动,暂时没找到这个bug,所以暂时采用响应WM_NCHITTEST消息方式,
在消息响应函数里面直接返回 HTCAPTION
1 LRESULT CLoginWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2 { 3 return HTCAPTION; 4 }