c - 为什么如果我禁用一个窗口,鼠标捕获会被释放,但如果我禁用其父窗口则不会释放鼠标捕获?

标签 c windows winapi event-handling mouse

我有一个带有主窗口和子窗口的 Win32 应用程序;在某些情况下,子窗口使用 SetCapture 捕获鼠标.

在这些情况下,如果我使用 EnableWindow(hChild, FALSE) 禁用子窗口,我会立即停止接收鼠标事件。但是,如果我使用 EnableWindow(hMainWindow, FALSE) 禁用其父窗口,则只要捕获鼠标,子窗口就会不断接收事件。一旦被释放,子窗口就会定期停止接收事件,直到主窗口再次启用。

为什么会出现这种差异?当其父窗口被禁用时,子窗口是否也会被禁用?

(受到我们今天工作中遇到的实际问题的启发,考虑到关于 SetCapture 等的讨论不多。我希望这对将来的人有所帮助)

最佳答案

Aren't child windows disabled as well when any of their parents is disabled?

当您禁用一个窗口时,从技术上讲,它的子窗口并没有被禁用 - 即使父窗口被禁用,如果您对其中任何一个窗口调用 IsWindowEnabled ,您都会得到 TRUE,并且它们不会具有 WS_DISABLED 样式。然而,它们实际上是被禁用的,因为通常它们不会收到任何输入。

这来自于被禁用的父窗口如何影响“常规”输入事件调度:当 Windows 必须调度鼠标事件时,它会递归地查找其客户区域包含光标的“最嵌套”窗口1 ,但在遇到禁用窗口时停止,并且不会对其子窗口进行递归。这可以确保即使是禁用窗口的子窗口通常也不会收到任何输入事件。

但是,当窗口捕获鼠标时,会绕过常规调度:所有鼠标事件都将直接调度到捕获窗口,无论它是否具有禁用的父窗口,或者即使它本身已禁用。

但是等等:这与观察结果不符:

if I disable the child window using EnableWindow(hChild, FALSE) I immediately stop receiving mouse events.

这来自于 EnableWindow不只是设置 WS_DISABLED 样式,而且还有一些额外的魔力;特别是

If the window is being disabled, the system sends a WM_CANCELMODE message.

引入此消息是为了要求接收窗口取消任何“临时”模式,例如打开菜单或捕获的鼠标,以准备禁用窗口,例如显示对话框:

For example, the system sends this message to the active window when a dialog box or message box is displayed. Certain functions also send this message explicitly to the specified window regardless of whether it is the active window. For example, the EnableWindow function sends this message when disabling the specified window.

这些任务是由默认窗口过程完成的:

When the WM_CANCELMODE message is sent, the DefWindowProc function cancels internal processing of standard scroll bar input, cancels internal menu processing, and releases the mouse capture.

因此,如果您愿意,可以通过在窗口过程中显式处理 WM_CANCELMODE 来完全禁用此行为,绕过默认处理(尽管我不推荐这样做)。在这种情况下,禁用子窗口本身将使鼠标捕获与 EnableWindow(hMainWindow, FALSE) 情况完全相同。


因此,最终的区别在于,EnableWindow 仅针对被禁用的窗口而不是其子窗口执行此额外技巧,因此如果其中任何一个窗口仍在捕获鼠标,它将保持被捕获状态。


注释

  1. 粗略地说;确切的过程有点复杂,最重要的是要考虑 z 顺序,忽略不可见的窗口,“分层”窗口需要特殊处理,...

关于c - 为什么如果我禁用一个窗口,鼠标捕获会被释放,但如果我禁用其父窗口则不会释放鼠标捕获?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64470164/

相关文章:

windows - 在没有可见控制台窗口的窗口中创建后台进程

c++ - 逆向工程全局热键 block

c++ - 如何确定进程的完整性级别?

c - 如何在不使用标准库函数的情况下打印内容?

c - Windows 中 Eclipse 上的 OpenCV242

windows - 调用 FileRead 后的奇怪计数值

c++ - 我是否需要 SE_SHUTDOWN_NAME 权限才能注销用户?

c - 从链表中释放函数时出错

c - 需要练习基于线性链表求解

c# - 如何在 c#.net windows 应用程序中检查 gridview 的行是否被选中