Qt QTimer在线程的应用与思考

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的时候遇到了一些问题。我希望测试一下QTimer,在一个界面上面点击开始计时按钮,便每隔0.5秒输出 “正在运行” 。 同时就在这个界面中,启动一个定时器,10秒之后输出“延时器输出!”

        具体的代码如下:

        头文件:

#ifndef VIDEO_H
#define VIDEO_H

#include <QDialog>
#include <QTimer>
#include <QtConcurrent/QtConcurrentRun>

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

        .cpp文件如下:

#include "video.h"
#include "ui_video.h"

#include <QDebug>
#include <QtConcurrent/QtConcurrentRun>
#include <QTimer>

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()<<"正在运行"<<endl;
        _sleep(500);
    }

}

void video::printword(){
    qDebug()<<"延时器输出!"<<endl;
}

        乍一看没什么问题,因为就是简单的循环输出“正在运行”,然后当计时器记够10s之后再输出 “延时器输出!” 。但是在实际运行中就出现了问题,程序一直循环输出“正在运行”,并且界面出现了卡死现象,不输出“延时器输出”字样。那么问题就来了,为什么会是这样呢?

        这是因为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()函数还是有些像的。

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值