我在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中不需要的激活事件。