前段时间在项目中遇到功能,实现一个自动锁屏的功能,说白了,就是通过某种手段实时监控鼠标和键盘的操作情况,在设定的时间内无操作时,调用自定义锁屏功能,我们选择使用重写QApplication类来实现。
Qt程序在运行到退出的过程中是一直在进行着事件循环,因此我们可以在事件循环中去截取信号,然后实现一些特殊的功能。
由于QApplication类在整个运行过程中都存在,我们也可以通过重写该类实现一些全局的功能。下面主要看下该类的实现,
首先我们定义一个类GlobalApplication继承自QApplication:
#include <QObject>
#include <QTimer>
#include <QApplication>
class GlobalApplication : public QApplication
{
Q_OBJECT
public:
GlobalApplication(int &argc, char **argv); //构造函数的参数与main()函数保持一致,**必须使用引用传值**
~GlobalApplication();
bool notify(QObject* obj, QEvent* event);
private slots:
void slot_timeOut();
private:
QTimer* m_pTimer; //定时器
QThread* m_pThread; //定时器线程
Mainwindow* m_pWidget; //执行锁屏功能的类
};
值得注意的一点:
QApplication,QCoreApplication和QGuiApplication的构造函数中,argc必须使用引用传值的方式,否则会崩溃
下面看下他的构造:
GlobalApplication::GlobalApplication(int &argc, char **argv) : QApplication(argc, argv)
, m_pTimer(Q_NULLPTR)
, m_pThread(Q_NULLPTR)
, m_pWidget(Q_NULLPTR) //该指针可以通过调用方法来设置
{
int nTimer = 5; //设置自动锁屏的超时时间,该时间可由配置文件导入
m_pThread = new QThread();
m_pTimer = new QTimer(this);
m_pTimer->moveToThread(m_pThread); //开启一个线程用来进行计时器的运行
connect(m_pThread, SIGNAL(started()), m_pTimer, SLOT(start()));
connect(m_pTimer, &QTimer::timeout, this, &GlobalApplication::slot_timeOut);
m_pTimer->setInterval(nTimer * 60000);
m_pThread->start();
}
/**实现超时槽函数,可在次函数中实现一些定时操作的任务**/
void GlobalApplication::slot_timeOut()
{
if (!m_pWidget || m_pWidget->isLockScreen())
{
return;
}
m_pWidget->lockScreen(); //定时任务
}
其中最主要的是实现notify函数, 该函数在程序运行过程中被不断的调用(事件循环)
bool GlobalApplication::notify(QObject* obj, QEvent* e)
{
if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::KeyPress)
{
m_pThread->quit();
}
else if (e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::KeyRelease)
{
m_pThread->start();
}
if (e->type() == QEvent::KeyPress)
{
/***********
*
* do something...
*
***********/
}
return QApplication::notify(obj, e);
}
void GlobalApplication::setWindowInstance(Mainwindow *wnd)
{
m_pWidget = wnd; /**可以将外部的类传进来**/
}
最重要的一点,我们需要将main.cpp中main()函数里面的QApplication替换为我们前面自定义的类。如下:
int main(int argc, char *argv[])
{
GlobalApplication a(argc, argv);
Style w;
w.show();
return a.exec();
}
以上,在我们需要一些全局操作来说,功能能够满足,重写该类的用途还有很多,比如在两个没有任何关系的类里面通过该类进行信号的传递。比如:
在设置信号的类里面通过调用:
auto application = dynamic_cast<GlobalApplication*>(QApplication::instance());
来获取全局QApplication的实例,然后通过调用GlobalApplication的方法设置信号,在获取信号的类里面同样能够获取到QApplication的实例,再调用方法来获取信号。
其实我们都知道,Qt的程序里面有个 qApp的全局对象,他的定义如下:
#define qApp (static_cast<QApplication *>(QCoreApplication::instance()))
那么猜想一下,我们能不能按照这种方式对我们自定义的 GlobalApplication
类也实现相同的对象呢?
#include <QObject>
#include <QTimer>
#include <QApplication>
class GlobalApplication;
#if defined(app )
#undef app
#endif
#define app static_cast<GlobalApplication*>(QCoreApplication::instance())
//#define app static_cast<GlobalApplication*>(QApplication::instance())
class GlobalApplication : public QApplication
{
Q_OBJECT
...
};
也就是说上面的这种实现方式可不可行,这样定义之后,我们就不会在后面的需要使用到GlobalApplication
对象的时候使用dynamic_cast<GlobalApplication*>(QApplication::instance());
这种方式去获取了。
通过验证,这种方式是可行的。