当在拖动/调整窗口大小的同时对窗口调用isActive()时,返回false.(X11,问题5.4.0)



我在linux(X11)上使用Qt 5.4.0,我需要确定我的窗口是否处于活动状态。因此,我编写了示例代码,如下所示。若那个些代码是在windows上编译的,那个么只有当windows并没有真正激活时,它才会在控制台中记录"false"。但在linux(X11)上,当我开始拖动或调整窗口大小时,它也会记录"false"。为什么会发生这种情况,以及如何在linux上修复这种情况?我想知道,我的窗口何时真正处于非活动状态,何时处于活动状态,但正在被拖动/调整大小。

代码段(C++):

void MainWindow::changeEvent(QEvent *e) {
    if (e->type() == QEvent::ActivationChange) {
        if (this->isActiveWindow()) {
            std::cout << "True" << std::endl;
        } else {
            std::cout << "False" << std::endl;
        }
    }
}

相同的代码,在PyQt5:上

import sys
from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtWidgets import QWidget, QApplication

class TransparentWidget(QWidget):
    def __init__(self):
        super(TransparentWidget, self).__init__()
    def changeEvent(self, e):
        if e.type() == QEvent.ActivationChange:
            print(self.isActiveWindow())
if __name__ == '__main__':
    app = QApplication(sys.argv)
    transparent_widget = TransparentWidget()
    transparent_widget.show()
    app.exec_()

它可能注册为"false",因为在X上,您看到的窗口实际上是两个窗口:一个是您绘制内容的窗口,另一个是稍大的窗口,它是您的父窗口,包含边框。

原因是X11没有"装饰边框"的概念,包括关闭/最大/最小按钮、标题栏、漂亮的渐变色、圆形边框等(原生X11窗口可以有边框,但只能是纯色或纹理)。这些控件由您的窗口管理器提供。如果您创建了一个窗口,那么窗口管理器会创建一个比您的窗口稍大的X11窗口,并将您的窗口作为子窗口放置在这个新窗口上。从那时起,这两个窗口紧密相连:调整窗口大小将调整父窗口的大小,反之亦然。

这一切都由窗口管理器处理。例如,如果你想调整窗口的大小并点击边框,点击不会进入你的窗口,而是进入窗口管理器,然后窗口管理器会确定点击的位置并决定如何处理。因此,此时你自己的窗口不再处于活动状态,这就解释了为什么isActiveWindow()返回false。

对于Microsoft Windows,边框是窗口本身不可分割的一部分,因此它保持"活动"状态。

无论如何,要确定您的窗口是否处于"活动"状态,您应该使用QFocusEvent。通过查看gotFocus()和lostFocs()值,您应该能够跟踪窗口何时处于活动状态。

活动窗口是当前接受键盘输入焦点的窗口,因此也是发送键盘事件的窗口。

在调整大小/移动操作期间,活动窗口不会注册键盘事件(无论它们是否实际发送)。鉴于此,在这样的操作过程中,窗口是否仍应被视为活动窗口是有争议的。

Qt4和Qt5在处理这一问题的方式上有所不同。在任何平台上调整大小/移动期间,Qt4都不会报告窗口激活变化(或焦点变化)(不过我只在X11和Windows上进行了实际测试)。Qt5也是如此——除了X11。

在X11上,Qt5在所有调整大小/移动操作的开始和结束时报告窗口激活变化(以及焦点变化)。也就是说,当操作开始时,isActiveWindow()返回False,当操作结束时返回True(并且还发送相应的FocusIn/FocusOut事件以及WindowActivate/WindowDeactivate事件,等等)。

可以说X11上的Qt5行为是唯一准确的。然而,它与Qt5支持的其他平台不一致,因此从开发人员的角度来看,它必须被认为是有缺陷的(或者至少是不方便的)。

尽管Qt4上的行为可以说不那么准确,但它至少在其支持的所有平台上都是一致的(即,这正是开发人员对跨平台工具包的期望)。

不幸的是,调整大小/移动事件仅在窗口激活更改后开始,因此似乎没有任何明显的方法来过滤Qt5中不需要的激活事件。

最新更新