当事件发生在 child 上时,我如何启动用户 mouse-driven 移动或调整 Windows 上的自定义 window 边框在无边框 window 上?

How do I initiate a user mouse-driven move or resize for custom window borders on Windows on a borderless window when the event comes to a child?

我有一个无边框的 window,其唯一的 child 始终是 window 的大小,是第三方组件。该组件希望能够通知我,当 WM_MOUSEDOWN 发生在某些区域时,由它自行决定移动或调整 window 的大小(就像它不是无边界的一样)。它还想决定要使用的事件。

因为window是无边框的,而childwindow已经收到了鼠标消息,我想我无法覆盖WM_NCHITTEST,我可以吗? (或者换句话说,parent window 总是在我的 child 获得 WM_LBUTTONDOWN 之前获得 WM_NCHITTEST 吗?还是仅在第一次 activation/during 捕获?)

GTK+ 过去常常用 WM_NCLBUTTONDOWN 调用 DefWindowProc() 来手动触发模态事件循环。这是方法吗?

WM_SYSCOMMAND中的SC_MOVE呢?这是否仅适用于 keyboard-driven window 移动和调整大小,而不适用于 mouse-driven 移动和调整大小?

还是我必须手动执行此操作?我知道它自己是一个模态循环,它使用消息过滤器常量之一,而且我知道 Aero Snap 至少需要手动完成。

我需要在 Windows Vista 或更高版本上执行此操作。

谢谢。

由于你的 parent window 是 border-less 并且完全被 child window 覆盖,parent 将不会收到 WM_NCHITTEST 默认。 child 将首先收到所有 WM_NCHITTEST 条消息。

但是,您仍然可以允许用户通过一些额外的编码正常调整 parent window 的大小。您可以通过几种不同的方式处理此问题:

  1. 子类 child window 以拦截 WM_NCHITTEST 消息。收到后,先将消息传递给child的默认消息处理程序,如果returns HTCLIENTlParam中提供的屏幕坐标在一个区域内要用于调整大小的 parent window,改为 return HTTRANSPARENT。这将导致 WM_NCHITTEST 接下来被发送到 parent window,然后它可以根据类型处理 WM_NCHITTEST 和 return 以下值之一调整大小:

    HTBOTTOM
    HTBOTTOMLEFT
    HTBOTTOMRIGHT
    HTLEFT
    HTRIGHT
    HTTOP
    HTTOPLEFT
    HTTOPRIGHT
    
  2. 在childwindow的mousedown事件中,将提供的鼠标客户端坐标转换成屏幕坐标,然后调用ReleaseCapture()发送一个WM_NCLBUTTONDOWN 消息到 parent window,将 wParam 设置为上述值之一,并将 lParam 设置为屏幕坐标。

  3. 在childwindow的mousedown事件中,调用ReleaseCapture()发送WM_SYSCOMMAND消息给parentwindow,将 wParam 设置为 SC_SIZE 加上下面的所需值,并将 lParam 设置为 0:

     SC_SIZE_HTLEFT = 1
     SC_SIZE_HTRIGHT = 2
     SC_SIZE_HTTOP = 3
     SC_SIZE_HTTOPLEFT = 4
     SC_SIZE_HTTOPRIGHT = 5
     SC_SIZE_HTBOTTOM = 6
     SC_SIZE_HTBOTTOMLEFT = 7
     SC_SIZE_HTBOTTOMRIGHT = 8
    

任何一种方式都将允许 parent window 正常调整大小,以及涉及的所有内容(鼠标跟踪、捕捉等),除了一件事。 #1 欺骗 OS 认为用户直接将鼠标悬停在 parent window 上,因此它允许 OS 提供有关 "sizing border" 的视觉反馈正在被使用。 #2 和 #3 不会提供任何视觉反馈,因此如果需要,您必须通过 SetCursor() 手动处理。

如果您希望允许用户拖动 parent window 而不调整它的大小,您可以:

  1. 子类 child WM_NCHITTEST 消息到 return HTTRANSPARENT 在适当的区域,然后有 parent window 处理 WM_NCHITTEST 到 return HTCAPTION.

  2. 在childwindow的mousedown事件中,调用ReleaseCapture()发送WM_SYSCOMMAND消息给parentwindow,将 wParam 设置为 SC_DRAGMOVE(未记录,但其值为 $F012,又名 SC_MOVE + 2),并将 lParam 设置为 0。