【问题标题】:How to capture the action about starting dragging a window and releasing the capture of a window?如何捕捉开始拖动窗口和释放窗口捕捉的动作?
【发布时间】:2021-03-07 09:01:11
【问题描述】:

当光标悬停在标题区域(HTCAPTION)上时,按鼠标左键,然后可以拖动一个窗口并移动它。当您释放鼠标左键时,您可以停止此拖动动作。当您移动一个窗口时,它会触发消息 WM_MOVE。当释放鼠标按钮时,我不知道应该处理哪个消息来捕捉这个动作。

我正在做的是当你将一个窗口(比如说窗口 A)拖到另一个窗口的区域(窗口 B)中时,使窗口 A 成为窗口 B 的子窗口,当将窗口 A 拖出窗口 B 的区域时,使窗口 A 一个 WS_POPUP 窗口,没有 WS_CHILD 样式。

我处理了消息 WM_MOVE 和 WM_CAPTURECHANGED(我认为这不是正确的)。 在 WM_CAPTURECHANGED 中,我发现了一些有线的东西。 API SetWindowPos 似乎无法正常工作。准确地说,第 3 和第 4 个参数指定了窗口的位置不起作用。

    case WM_CAPTURECHANGED: {
        RECT rcc;
        GetClientRect(main,&rcc); 
        // here main is the handler of window B , hwnd is for window A,as referrence above.
        
        if(docker_mode==DOCKER_LEFT) { 
            // docker_mode is assigned by WM_MOVE message handler. recording which area window A was moved into.  
            
            if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))!=WS_CHILD) {
                SetWindowLongPtr(hwnd,GWL_STYLE,(~WS_POPUP)&(WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE)));
                SetParent(hwnd,main);
            }

            //The following code not work. It should be moved into the left-top corner of window B, 
            //but NOT in fact. 
            SetWindowPos(hwnd,NULL,0,0,300,rcc.bottom-rcc.top,SWP_NOZORDER);
        }
        else {
            if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))==WS_CHILD) {
                SetWindowLongPtr(hwnd,GWL_STYLE,((~WS_CHILD)&GetWindowLongPtr(hwnd,GWL_STYLE))|WS_POPUP);
                SetParent(hwnd,NULL);
                SetWindowPos(hwnd,NULL,300,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
            }
        }
        
    } break;

SetWindowLongPtr(...,GWL_STYLE,...) 被调用来设置窗口样式。顶层没有 WS_CHILD 样式,父窗口的句柄应该是 NULL ,我用 SetParent(hwnd,NULL) 来做这个。子窗口应该有 WS_CHILD 样式,并且应该分配父窗口。

我在窗口中放了一个按钮,并将这些代码复制到按钮单击事件的句柄中。单击按钮效果很好,将弹出窗口更改为子窗口,将子窗口放在正确的位置。 SetWindowPos 完全没有问题。我不知道为什么。

SetWindowPos 在处理 WM_CAPTURECHANGED 处理程序时是一个非常有趣的 API。怎么了?

【问题讨论】:

    标签: windows


    【解决方案1】:

    如果我没记错的话,当用户拖动一个窗口时,该窗口会收到如下消息序列:

    1. WM_ENTERSIZEMOVE
    2. WM_WINDOWPOSCHANGING
    3. WM_MOVING
    4. WM_WINDOWPOSCHANGED
    5. WM_MOVE
    6. WM_EXITSIZEMOVE

    (也有其他消息,但我认为您不必担心这些消息。在 WM_EXITSIZEMOVE 之后可能会有一些最终消息以及窗口的最终休息位置。)

    当用户拖动窗口时,中间的步骤会重复发生。 (在过去,这些中间步骤只会发生一些,并且可能仍然可以选择在拖动操作期间减少消息。)

    您可以尝试使用 Spy++(包含在 Visual Studio 中)来确认上述内容。

    因此您不需要处理鼠标捕获消息。有窗口 A 监视 WM_EXITSIZEMOVE。此时,窗口 A 可以检查其位置以查看它是否与目标窗口 (B) 重叠。如果确实重叠,则应向窗口 B 发送消息以启动停靠操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-01
      • 1970-01-01
      • 2010-11-04
      • 2012-08-24
      • 1970-01-01
      • 2012-09-30
      • 1970-01-01
      相关资源
      最近更新 更多