Windows 上的 Qt 5.4.0,在某些情况下 returns 上调用 QWidget 的 isActive() 显然是错误的值

Qt 5.4.0 on Windows, isActive() called on QWidget in some cases returns obviously wrong value

在某些情况下,在 Windows 平台上,isActive() 在 QWidget 上调用 returns true,显然,它不能激活。

例如,我的应用程序在 GUI 线程上做了很多工作,并在启动后显示 window 有一些延迟。如果我启动应用程序并在应用程序显示 main window 之前切换到另一个应用程序,当显示 window 时,它肯定会处于非活动状态。但是在这种情况下调用 isActive() returns true。如果我切换到我的应用程序并切换回另一个应用程序,isActive() 将像往常一样为 false。但一开始它是真的,这不是通常应该是的。顺便说一下,在 linux 和 OS X 上它按计划工作。

我该如何解决?或者我该如何解决?

重现该问题的示例代码如下。这是 PyQt,但相信我,Qt 也重现了这个问题。

import sys
from time import sleep
from PyQt5.QtWidgets import QWidget, QApplication

class BadWidget(QWidget):
    def __init__(self):
        super(BadWidget, self).__init__()
        self.startTimer(500)

    def timerEvent(self, e):
        print(self.isActiveWindow() and not self.isMinimized())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    bad_widget = BadWidget()
    sleep(1)
    bad_widget.show()
    app.exec_()

错误的解决方案:在请求小部件状态之前调用 QApplication::processEvents()

好的解决方案:通过QtConcurrent或其他多线程方式在线程池中"much work"

你可以试试isVisible() && isActiveWindow() && !isMinimized()

最后,我找到了一些完全符合我要求的可行解决方案。不幸的是,它只能使用 WinAPI 调用来完成,但没关系。

大意是在Windows上,"active"和"foreground"window不是一回事。更多信息在这里:

最终解决方案如下所示:

if sys.platform.startswith('win'):
    if ctypes.c_long(self.effectiveWinId()).value ==\
            windll.user32.GetForegroundWindow():
        # active
    else:
        # inactive
else:
    if self.isActiveWindow():
        # active
    else:
        # inactive