2种情况可能造成:QObject::startTimer: Timers cannot be started from another thread

一、分析 2 种情形,这里重现一下

1、一般情况


这种一般比较常见

1、创建自定义类型 MyTest

2、头文件 mytest.h

#ifndef MYTEST_H
#define MYTEST_H

#include <QThread>
#include <QTimer>

class MyTest : public QThread
{
    Q_OBJECT
public:
    explicit MyTest(QObject *parent = nullptr);

protected:
    virtual void run() override;

signals:

private:
    QTimer *m_timer;

};

3、源文件 mytest.cpp

#include "mytest.h"

MyTest::MyTest(QObject *parent) : QThread(parent)
{
    m_timer = new QTimer();
    start();
}

// 子线程
void MyTest::run()
{
    m_timer->start(100);
}

调试结果

 

然后

至于为什么这样,它已经给出明确的提示

QTimer 不能在不同线程中启动

解决方案也比较简单

把 QTimer 的操作都放在同一个线程即可

修改下源文件 mytest.cpp

#include "mytest.h"

MyTest::MyTest(QObject *parent) : QThread(parent)
{
    start();
}

// 子线程
void MyTest::run()
{
    m_timer = new QTimer();
    m_timer->start(100);
}

完成

2、其他情况


这种情况隐藏的深一点

我们使用一个串口类来演示

测试函数:主要功能是向串口里面写入数据

void MyTest::onSaveDatas(QByteArray buf)
{
    // 打开串口
    if(m_serial == nullptr){
        m_serial = new QSerialPort();
        m_serial->setPortName("COM1");
        m_serial->open(QIODevice::ReadWrite);
    }

    // 写入串口
    m_serial->write(buf);
}

调用方式

    MyTest *obj = new MyTest();       // 创建对象 obj
    QThread *thread1 = new QThread(); // 创建线程 thread1
    obj->moveToThread(thread1);       // 将对象移动到 thread1 子线程中
    thread1->start();                 // 开启 thread1 子线程

    // 信号槽连接
    connect(this, &Widget::sig_save_data, obj, &MyTest::onSaveDatas);

    emit sig_save_data("123"); // 发射写信号
    QThread::msleep(1000);     // 测试使用,暂停一会儿
    obj->onSaveDatas("123");   // 调用写入

 调试结果

 可以看到,我们并没有使用 QTimer 

但它却产生了这样的信息

会给我们带来不明确的方向,花费大量的时间去 debug

还可能找不到问题点

。。。

那如何修正

因对象已经被移动到子线程

这时候

推荐使用信号槽的方式去交互

尽量不要直接以调用方式去使用

修改一下

    emit sig_save_data("123"); // 发射写信号
    QThread::msleep(1000);     // 测试使用,暂停一会儿
    //obj->onSaveDatas("123");   // 调用写入  ***不使用这种方式

 这样它就不会产生那样的信息啦

***完整工程代码

mytest.h 

#ifndef MYTEST_H
#define MYTEST_H

#include <QObject>
#include <QtSerialPort/QSerialPort>

class MyTest : public QObject
{
    Q_OBJECT
public:
    explicit MyTest(QObject *parent = nullptr);

public:
    void onSaveDatas(QByteArray buf);

signals:

private:
    QSerialPort *m_serial = nullptr;

};

#endif // MYTEST_H

mytest.cpp 

#include "mytest.h"

#include <QThread>

MyTest::MyTest(QObject *parent) : QObject(parent)
{

}

void MyTest::onSaveDatas(QByteArray buf)
{
    // 打开串口
    if(m_serial == nullptr){
        m_serial = new QSerialPort();
        m_serial->setPortName("COM1");
        m_serial->open(QIODevice::ReadWrite);
    }

    // 写入串口
    m_serial->write(buf);
}

widget.h  

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

signals:
    void sig_save_data(QByteArray buf);

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

 widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QThread>
#include "mytest.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    MyTest *obj = new MyTest();       // 创建对象 obj
    QThread *thread1 = new QThread(); // 创建线程 thread1
    obj->moveToThread(thread1);       // 将对象移动到 thread1 子线程中
    thread1->start();                 // 开启 thread1 子线程

    // 信号槽连接
    connect(this, &Widget::sig_save_data, obj, &MyTest::onSaveDatas);

    emit sig_save_data("123"); // 发射写信号
    QThread::msleep(1000);     // 测试使用,暂停一会儿
    //obj->onSaveDatas("123");   // 调用写入
}

Widget::~Widget()
{
    delete ui;
}

 

二、_End


测试环境

Qt Creator 5.12.8

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值