Duilib改进窗口拖动,使整个窗口都能拖动(转载)

Posted 车臣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Duilib改进窗口拖动,使整个窗口都能拖动(转载)相关的知识,希望对你有一定的参考价值。

转载: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 }

 

以上是关于Duilib改进窗口拖动,使整个窗口都能拖动(转载)的主要内容,如果未能解决你的问题,请参考以下文章

Duilib界面拖动问题

在 qml 中拖动无框窗口“抖动”

DuiLib的Combo控件点击无响应的问题

如何使窗口可拖动(C# Winforms)?

如何通过拖动扩展的窗口框架使 WPF 窗口可移动?

使 javascript 弹出窗口可拖动