QT线程之 moveToThread() 只能用信号槽方式触发

qt的线程使用方法有把某个对象的函数放置线程里执行,方法为moveToThread()

具体操作步骤为:
1、创建一个新的类,让这个类从 QObject 派生

class MyWork:public QObject
{
    .......
}

2、在这个类中添加一个公共的成员函数,函数体就是我们要子线程中执行的业务逻辑

class MyWork:public QObject
{
public:
    .......
    // 函数名自己指定, 叫什么都可以, 参数可以根据实际需求添加
    void working();
}

3、在主线程中创建一个 QThread 对象,这就是子线程的对象

QThread* sub = new QThread;

4、在主线程中创建工作的类对象(千万不要指定给创建的对象指定父对象)

MyWork* work = new MyWork(this);    // error
MyWork* work = new MyWork;          // ok

5、将 MyWork 对象移动到创建的子线程对象中,需要调用 QObject 类提供的 moveToThread() 方法

// void QObject::moveToThread(QThread *targetThread);
// 如果给work指定了父对象, 这个函数调用就失败了
// 提示: QObject::moveToThread: Cannot move objects with a parent
work->moveToThread(sub);	// 移动到子线程中工作

6、启动子线程,调用 start(), 这时候线程启动了,但是移动到线程中的对象并没有工作
7、信号槽调用 MyWork 类对象的工作函数,让这个函数开始执行,这时候是在移动到的那个子线程中运行的,需要外面的信号传来让MyWork执行工作函数。

下面是一套完整的工程:

//mywork.h
#ifndef MYWORK_H
#define MYWORK_H

#include <QObject>

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

    // 工作函数
    void working();

signals:
    void curNumber(int num);

public slots:
};

#endif // MYWORK_H
//mywork.cpp
#include "mywork.h"
#include <QDebug>
#include <QThread>

MyWork::MyWork(QObject *parent) : QObject(parent)
{

}

void MyWork::working()
{
    qDebug() << "当前线程对象的地址: " << QThread::currentThread();

    int num = 0;
    while(1)
    {
        emit curNumber(num++);
        if(num == 1000)
        {
            break;
        }
        QThread::usleep(1);
    }
    qDebug() << "run() 执行完毕, 子线程退出...";

}
//widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QString>
#include<QThread>
#include "mywork.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    
private slots:
    void on_pbStart_clicked();
    void setNum(int num);
    
private:
    Ui::Widget *ui;
    MyWork *work;
    QThread* sub;
};
#endif // WIDGET_H
//widget.cpp
#include "widget.h"
#include "ui_widget.h"


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 创建线程对象
     sub = new QThread;
     // 创建工作的类对象
     // 千万不要指定给创建的对象指定父对象
     // 如果指定了: QObject::moveToThread: Cannot move objects with a parent
     work = new MyWork;
     // 将工作的类对象移动到创建的子线程对象中
     work->moveToThread(sub);
     // 启动线程
     sub->start();
     // 让工作的对象开始工作, 点击开始按钮, 开始工作
     connect(ui->pbStart, &QPushButton::clicked, work, &MyWork::working);
     // 显示数据
     connect(work, &MyWork::curNumber, this, &Widget::setNum);

}

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

void Widget::on_pbStart_clicked()
{
//    work->working();  //这个有点坑,下面重点讲!
}

void Widget::setNum(int num)
{
    ui->lb_time->setText(QString::number(num));
}

重点来了! 最主要的问题就是子对象的working()函数到底由谁来触发的问题
对比原因在注释写的很清楚了

//正解,主线程点击按钮只是触发信号,而working是由work自己来触发的,并且在子线程执行
connect(ui->pbStart, &QPushButton::clicked, work, &MyWork::working);
//错误示范❌,原因在于下面两个都是指定working由主线程来触发,本质是执行主线程的槽函数
void Widget::on_pbStart_clicked()  //本质上这是个槽函数,点击按钮就执行这个槽函数
{
    work->working();  //因为work对象在主线程里定义的,如此执行working也是在主线程
}
//或者
connect(ui->pbStart,&QPushButton::clicked,[=](){
    work->working();  //这和上面on_pbStart_clicked()里被调用没有区别
});
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值