一、分析 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