Qt中提供了QTimer计时器,可以单次或者多次触发,当计时结束的时候利用connect()函数可以触发自己想要的函数,具体实现如下:
创建定时器,并且和计时结束之后发射的槽函数信号连接起来:
QTimer *timer = new QTimer;
connect(timer,SIGNAL(timeout()),this,SLOT(func1()));//当计时器结束之后timeout函数触发自己的func1函数
timer->start(10000);//开始计时器,设置时间超时值为10秒
//停止计时器
if(timer->isActive())
timer->stop();
但是我在写一个QTimer的时候遇到了一些问题。我希望测试一下QTimer,在一个界面上面点击开始计时按钮,便每隔0.5秒输出 “正在运行” 。 同时就在这个界面中,启动一个定时器,10秒之后输出“延时器输出!”
具体的代码如下:
头文件:
#ifndef VIDEO_H
#define VIDEO_H
#include
#include
#include
namespace Ui {
class video;
}
class video : public QDialog
{
Q_OBJECT
public:
explicit video(QWidget *parent = 0);
~video();
private slots:
void on_pushButton_clicked();
void printword();
signals:
void sendsignal();
private:
Ui::video *ui;
QTimer *timer;
};
#endif // VIDEO_H
#include "video.h"
#include "ui_video.h"
#include
#include
#include
video::video(QWidget *parent) :
QDialog(parent),
ui(new Ui::video)
{
ui->setupUi(this);
this->setAttribute(Qt::WA_DeleteOnClose,1);
timer = new QTimer;
connect(timer,SIGNAL(timeout()),this,SLOT(printword()));
}
video::~video()
{
delete ui;
}
void video::on_pushButton_clicked()
{
timer->start(10000);
while(!stop){
qDebug()<<"正在运行"<
这是因为QTimer是由事件驱动的,当我们调用start(10000)函数的时候,当计时器10s结束之后就会向事件队列中插入一个超时事件,Qt解析发现了这个时间,那么就根据connect找到我自己的func1函数进行处理。但是注意,我自己的点击按钮写的是一个无限循环,并且这个无限循环在计时器结束之前就开始了,所以无论怎么样Qt都不会找到这个超时事件了,因为它一直在处理那个无限循环,这也是单一的线程的局限性。
所以这也给我们提了一个醒。对于界面上面如果有计时器,一定要慎重,尤其看到无限循环这种,很容易就会让界面卡死,所以我们应该用多线程来解决。解决方案如下,在界面的构造函数中新加一个线程:
// 新开一个线程来开启定时器
_thread = new QThread;
timer = new QTimer;
timer->setSingleShot(true);//只是单次触发
timer->start(10000);//开启计时
timer->moveToThread(_thread);
// 定时器对象和this不在一个线程里面,这边指定了连接方式为Qt::DirectConnection,超时后直接触发
connect(_timer, SIGNAL(timeout()), this, SLOT(printword()), Qt::DirectConnection);
_thread->start();
我这个写的有些简介了,事实上新建线程需要重新继承QThread类,我这里面省略了,如果不太明白的话网上有很多教程,我只是把最关键的部分放上来了。但是整体思想就是因为无限循环会阻塞自己的计时器超时事件,所以我们需要另开一个线程来执行计时器。当然,如果在这个线程中没有无限循环,Qt最终会接触到时间队列中的计时器超时事件,那么就不用麻烦多开一个线程了,直接写QTimer即可,从这个角度来说和_sleep()函数还是有些像的。