上一篇文章讲解了实现思路,最终选中使用线程池的方式解决,这篇文章主要讲解如何使用该方式进行具体实现。
功能实现
开发环境:win10 VS2017 + Qt5.14.2
1:实现监听线程
每进行一次操作都需要从当前操作开始计时,当时间超过设定时间5分钟后,监听线程发出消息通知使用者,已经超时了。
主要的实现技术采用线程池方式:QThreadPool
1.1:自定义线程类
继承类名称:QListeningActiveThread,继承自QRunnable
添加头文件
#include <QThreadPool>
继承的简单框架,如下所示:
class QListeningActiveThread : public QObject, public QRunnable
{
Q_OBJECT
public:
QListeningActiveThread();
~QListeningActiveThread();
private:
void run();
};
一般情况下,线程的处理是在run函数中处理。
1.2:run函数处理思想
当启动线程时,run函数就开始工作了。
核心思路:run需要启动一个while循环,一直在判断是否超时,每当有新的操作时,需要更新最新激活时间,当时间差超过设定时间时,发送消息通知外部使用者。
代码如下:
void QListeningActiveThread::run()
{
//在线程池的处理,每间隔1s就遍历一次,直到达到定时器时间为止
int nTimeout = m_nMinutes * 60 * 1000; //超时时间
while (true)
{
QThread::msleep(1000);
if (m_bStopThread == true)
{
qDebug() << QStringLiteral("监听激活线程,突然中断了定时器!");
break;
}
DWORD dwCalc = GetTickCount() - m_dwCurrentTime;
if (dwCalc > nTimeout)
{
qDebug() << QStringLiteral("监听激活线程,当前程序已经2分钟无操作,需要强制停止程序!");
emit Msg_SendListeningActiveTimeout();
break;
}
}
qDebug() << QStringLiteral("监听激活线程,此时run函数自动结束!");
}
代码解析:
m_bStopThread:用户控制是否需要从外部强制停止线程。
m_dwCurrentTime:最新的激活时间。
dwCalc:时间差,每次循环的最新时间 - 最新激活时间,当时间差超过设定的超时时间
由此产生了三个对外开放接口
1.3:外部调用接口
1.3.1:设置超时时间
void QListeningActiveThread::SetTimeoutPeriod(int nMin)
{
m_nMinutes = nMin;
}
1.3.2:停止当前线程
void QListeningActiveThread::StopCurrentThread()
{
m_bStopThread = true;
}
1.3.3:更新激活时间
void QListeningActiveThread::UpdateActiveTime(DWORD dwCurrentTime)
{
m_dwCurrentTime = dwCurrentTime;
}
2:继承QApplication
继承QApplication类,新类名:GlobalApplication
简单继承方式,如下
class GlobalApplication : public QApplication
{
Q_OBJECT
public:
GlobalApplication(int &argc, char **argv);
~GlobalApplication();
}
2.1:捕获鼠标按下消息
重写QApplication::notify消息
bool GlobalApplication::notify(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress)
{
qDebug() << QStringLiteral("自定义 QApplication类,接口鼠标按下消息");
//具体的实现在这里操作
}
return QApplication::notify(obj, event);
}
2.2:使用线程监听类
构造该函数中创建线程
m_pThread = new QListeningActiveThread;
connect(m_pThread, &QListeningActiveThread::Msg_SendListeningActiveTimeout, this, &GlobalApplication::MsgReceived_TimeoutApp);
每当收到线程类发送的Msg_SendListeningActiveTimeout消息时,代表界面已经超过限定时间了,需要通知外界,后续的使用就不再多说了,该做什么页面操作大家就自行发挥了。
此时线程创建后,并不立即启动,由外部调用者来决定是否要开启线程
2.3:开启线程监听
void GlobalApplication::StartListening()
{
m_pThread->UpdateActiveTime(GetTickCount()); //获取系统最初时间
QThreadPool::globalInstance()->start(m_pThread);
}
2.4:结束线程监听
void GlobalApplication::EndListening()
{
m_pThread->StopCurrentThread();
delete m_pThread;
}
2.5:实时更新激活时间
void GlobalApplication::RealtimeUpdateActiveMsg()
{
m_pThread->UpdateActiveTime(GetTickCount());
}
每当捕获到鼠标事件后,需要调用该函数进行时间更新,notify代码完善,如下所示:
bool GlobalApplication::notify(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress)
{
//qDebug() << QStringLiteral("自定义 QApplication类,接口鼠标按下消息");
this->RealtimeUpdateActiveMsg(); //实时更新选中时间
}
return QApplication::notify(obj, event);
}
还有一种情况,每当进行UI绘图时,是无法再notify中进行捕获的,此时,需要由使用者外部调用RealtimeUpdateActiveMsg函数,实时更新,想在哪里调用都可以。
3:具体程序调用
3.1:main函数使用
系统默认的main.cpp中,是调用QApplication,此时需要修改为GlobalApplication
修改代码如下:
#include "QtCaptureMouseEvent.h"
#include <QtWidgets/QApplication>
#include "GlobalApplication.h"
int main(int argc, char *argv[])
{
//QApplication a(argc, argv);
GlobalApplication a(argc, argv);
QtCaptureMouseEvent w;
w.show();
return a.exec();
}
3.2:调用开启线程抓取消息功能
其中,QtCaptureMouseEvent是mian.cpp中调用的主页面,此时需要将开启线程的功能写到该类的构造函数中,只开启一次,并销毁一次,防止多次创建和销毁。
难点:该如何调用GlobalApplication中的函数呢?
调用方式,如下:
auto appSelf = dynamic_cast<GlobalApplication*>(QApplication::instance());
appSelf ->StartListening(); //开启监听
connect(appSelf, &GlobalApplication::Msg_SendGlobalApplication_ListeningTimeout, this, &MiseStudent2::MsgReceived_GlobalApplication_ListeningTimeout);
首先要获取类直线,再进行后续操作。
目前有个问题,外部使用者每次都要调用指针进行转换很不方便,为了外部调用者能够简单应用,此时需要设定一个预处理指定,就类似于qApp使用一样。
class GlobalApplication;
#if defined(appGlobal)
#undef appGlobal
#endif
#define appGlobal static_cast<GlobalApplication*>(QApplication::instance())
只需要将上述几行代码放到GlobalApplication自定义类前面就可以了,后续再使用时,就可以用appGolbal代替指针转化啦,是不是很方便?
结束
到这里主要核心代码已经实现了,有需要工程的小伙伴可以下载哟~
我是糯诺诺米团,一名C++开发程序媛~