如何以正确的顺序禁用与使能窗口(回归激活窗口)(Win32)

陪她去流浪 桃子 2015年10月27日 编辑 阅读次数:2617

本篇文章翻译于:The Old New Thing: The correct order for disabling and enabling windows,有删改。

如果你想显示模态窗口,你需要使能将要模态的窗口(被拥有者(Owned))和禁用掉拥有者窗口(Owner)(原文貌似有笔误)。当模态窗口需要关闭的时候,把这个操作反过来进行。

如果没有正确地完成该操作,窗口焦点将会变得一团糟。

比如,像下面这样:

  • 销毁掉模态窗口;
  • 重新使能拥有者窗口;

,但是很不幸,如果你这样做的话,你会发现焦点窗口将回不到你原来的拥有者窗口。取而代之的是随机一个窗口(很有可能不是当前进程的)。 当然,可以通过API(SetFocus, SetActiveWindow, SetForegroudWindow, BringWindowToTop, ...)尝试显式地激活窗口来做到,但我一定坦诚地告诉你,这绝对不容易!因为这涉及到权限,比如:你是否有SetForegroupWindow权限? 再者,就算你“修复”了此问题,但极有可能会出现窗口闪烁、Z序错乱等更加恼人的问题。

到底发生了什么事情?

当你销毁掉模态窗口的时候,你应该意识到你销毁的是一个前台激活的窗口。Windows的窗口管理器现在需要找到另外一个窗口给予激活并成为前台窗口。它会尝试把它给予模态对话框的拥有者,但不幸的是,它现在仍然处理被禁用状态。 于是,于是窗口管理器抛弃它,并选择另一个窗口,另一个未被禁用的窗口(可能是其它程序的)。

这就是你为什么导致出现了奇怪的窗口进入了前台并激活。

因此,销毁一个模态窗口的正确做法是:

  • 先使用拥有者窗口;
  • 然后再销毁模态窗口;

,这个时机恰好可以是(1)在把 WM_CLOSE 传递给 DefWindowProc 之前,(2)在调用 DestroyWindow 之前。

这样一来,当你的模态窗口销毁时,窗口管理器就能正确地找到未被禁用的所有者窗口,所以,它继承了激活特性。

不会再有窗口闪烁,不会再有不预期的其它窗口擅自闯入。

参考

标签:WinAPI