Qt|实现5分钟无操作自动关闭程序功能<2>

上一篇文章讲解了实现思路,最终选中使用线程池的方式解决,这篇文章主要讲解如何使用该方式进行具体实现。

功能实现

开发环境: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++开发程序媛~

  • 23
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糯诺诺米团

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值