Qt 杂谈 —— Qt中捕获某个窗口的停用和**的消息处理不同情况 —— Activate & Deactivate
Qt中捕获某个窗口的停用和**的消息处理不同情况 —— Activate & Deactivate
背景&原理说明
背景
本人由于最近接到一个需求,很奇特,就是让一个窗口在MainWindow**的时候,设置成最顶层窗口,但是在非**又不是最小化的状态下,处于非顶层,不然就会出现一种神奇的bug,就是当前主窗口为非**状态时,某些窗口依旧悬浮在顶层盖住了其他应用的显示区域,这就非常的奇怪。
因此正在网上搜集资料的时候,看到了一个很有意思的文章(具体见参考文章),解决了我一部分工作中遇到的问题,主要是给我提供了一个崭新的思路去解决一些问题,虽然最终还是没有完全解决我工作中遇到的这个bug,但是确实这里值得我来记录一下,作为一个学习和思考的笔记。不过最后还是要说,自己组长厉害就是厉害,经验就是到位,这个问题被我组长用另外一个方案,利用QApplication的Activate和InActive的状态来完美解决了。
当然,如果有什么新的思路,或者是觉得我写的有什么错误,也欢迎大家批评指导。
原理
void QWidget::focusOutEvent ( QFocusEvent * event ) [virtual protected]
同样一开始,我跟参考文献中的作者思考的是一样的,重写FocusOutEvent可以解决这个问题,同样,我试了试,发现了自己的天真可爱。直到我找到了我参考的文章,我才明白为什么他没用,因为这是个跨线程的操作,所以我根本就不在你那个线程里面了你再怎么Focus也没用啊。
任何一个时候,我们的Windows桌面上总有一个最前台的窗口,其实说简单的,就是标题栏变成深蓝色的那个窗口,仅此一个,这个窗口就是前景窗口(Foreground Window),其他窗口就是后台窗口(Background Window)。那创建前景窗口的线程就是前景线程(Foreground Thread),这个线程并不一定就是应用程序的主线程。
线程内部会维护当前自己的活动窗口(Active Window)和焦点窗口(Focus Window), 焦点窗口其实只是窗口的一个属性,其实就是“焦点状态”是窗口的一个属性,而焦点窗口的顶层窗口就是活动窗口,举个例子:一个对话框中有一个按钮,当按钮 获得焦点的时候,那此按钮就是焦点窗口,则包含此按钮的对话框就是活动窗口,若出现窗口嵌套的情况,则最根的那个窗口才是活动窗口。(以上文字引自参考的文章 )
代码案例
那么从实践的角度来讲,我在参考文章的示例代码基础上,写了个小demo调试了一下。具体代码如下:
首先 , main.cpp:
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#include "activate_window.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ActivateWindow w;
w.show();
return a.exec();
}
接下来, activate_window.h:
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#ifndef _ACTIVATE_WINDOW_H_H_
#define _ACTIVATE_WINDOW_H_H_
#include <QtWidgets/QMainWindow>
#include "ui_activate_window.h"
class ActivateWindow : public QMainWindow
{
Q_OBJECT
public:
ActivateWindow(QWidget *parent = Q_NULLPTR);
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private:
Ui::ActivateWindowClass ui;
};
#endif // !_ACTIVATE_WINDOW_H_H_
最后, activate_window.cpp:
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#include <QtCore/QEvent>
#include "activate_window.h"
ActivateWindow::ActivateWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
installEventFilter(this);
}
bool ActivateWindow::eventFilter(QObject * watched, QEvent * event)
{
if (watched == this)
{
//窗口停用,变为不活动的窗口
if (QEvent::WindowDeactivate == event->type())
{
//
//DEBUGP( "eventFilter" ) ;
// hide(); //或者关闭窗口,加入自己的操作.
setStyleSheet("QWidget { background-color : red; }");
return true;
}
else
{
// setStyleSheet("QWidget { background-color : blue; }");
return false;
}
}
return false;
}
项目中的实际应用举例
在本人项目中,找到了另外一种利用QApplication的状态监听来改变对应的状态的解决办法,该办法合理的解决了窗口顶层的问题, 具体代码示意如下,主要理解想法,代码上下文不方便提供:
在初始化函数中:
connect(qApp, &QApplication::applicationStateChanged, [this](Qt::QpplicationState state)
{
if(!windowHandle())
{
return;
}
if (state & Qt::ApplicationActive)
{
windowHandle()->setFlag(Qt::WindowStaysOnTopHit);
}
else if (state & Qt::ApplicationInactive)
{
windowHandle()->setFlag(Qt::WindowStaysOnTopHit, false);
}
});
通过上面的逻辑我们不难发现,捕获App的状态修改,我们可以在主窗口**和非**状态下,完成一些不同的操作。
参考文章
Qt 中如何捕获窗口停用和**的消息 Activate&Deactivate
个人格言
用心去感受你自己需要坚持的生活,未来慢慢会给你答案的。
上一篇: Anaconda使用conda activate**环境出错
下一篇: Dubbo SPI详解