Qt:线程

一个Qt窗口生成后,为什么拖动窗口,窗口可以随着鼠标移动或放大缩小

因为对窗口操作后,都有对应的事件产生,Qt在其框架中对这些事件进行了默认处理

一个Qt程序默认只有一个线程,称为主线程(也叫ui线程),主要处理窗口的事件(比如鼠标拖动,缩放,窗口控件对象数据的更新)

不能用子线程处理这些事,如果子线程要操作窗口,只能先将数据传递给主线程,由主线程操作

常用函数

分为三个部分,公有函数、公有槽函数,信号,Qt提供的静态成员函数

父对象和父类是两回事,父类是继承关系,父对象是从属关系

cpp 复制代码
// 构造函数
QThread::QThread(QObject *parent = Q_NULLPTR);
指定一个父对象就可以了

// 判断线程中的任务是不是处理完毕了
bool QThread::isFinished() const;
// 判断子线程是不是在执行任务
bool QThread::isRunning() const;

// Qt中的线程可以设置优先级
// 得到当前线程的优先级
Priority QThread::priority() const;
void QThread::setPriority(Priority priority);
优先级:
    QThread::IdlePriority         --> 最低的优先级
    QThread::LowestPriority
    QThread::LowPriority
    QThread::NormalPriority
    QThread::HighPriority
    QThread::HighestPriority
    QThread::TimeCriticalPriority --> 最高的优先级
    
    QThread::InheritPriority      --> 子线程和其父线程的优先级相同, 默认是这个
cpp 复制代码
// 退出线程, 停止底层的事件循环
// 退出线程的工作函数
void QThread::exit(int returnCode = 0);
// 调用线程退出函数之后, 线程不会马上退出因为当前任务有可能还没有完成, 调回用这个函数是
// 调用wait后会等待任务执行, 执行完退出线程, 一般情况下会在 exit() 后边调用这个函数
bool QThread::wait(unsigned long time = ULONG_MAX);

cpp 复制代码
// 和调用 exit() 效果是一样的
// 调用这个函数之后, 再调用 wait() 函数
[slot] void QThread::quit();

// 启动子线程
[slot] void QThread::start(Priority priority = InheritPriority);

// 线程退出, 可能是会马上终止线程, 一般情况下不使用这个函数
[slot] void QThread::terminate();

信号

cpp 复制代码
// 线程中完成后, 会发出该信号
[signal] void QThread::finished();

// 发出该信号后表示线程开始工作,启动线程后没必要捕捉该信号
[signal] void QThread::started();

主线程和子线程间通过信号和槽进行数据传递

静态函数

cpp 复制代码
// 返回一个指向管理当前执行线程的QThread的指针
[static] QThread *QThread::currentThread();

// 返回可以在系统上运行的理想线程数 == 和当前电脑的 CPU 核心数相同
[static] int QThread::idealThreadCount();

// 线程休眠函数
[static] void QThread::msleep(unsigned long msecs);	// 单位: 毫秒
[static] void QThread::sleep(unsigned long secs);	// 单位: 秒
[static] void QThread::usleep(unsigned long usecs);	// 单位: 微秒

任务处理函数

c 复制代码
// 子线程要处理什么任务, 需要写到 run() 中
[virtual protected] void QThread::run();

该函数没有参数和返回值,是一个受保护的虚函数,如果让子线程处理某些任务,需要将任务写到run内部,调用start函数就能执行线程内部的run函数

受保护说明该函数不能在类外使用,需要通过调用start槽函数使run函数运行执行任务

使用方式

方式1:

  • 创建线程类,该类继承QThread类
  • 在线程的子类中重写run函数
  • 在主线程类中new一个子线程的类对象,让该子线程对象调用start函数

子类头文件

cpp 复制代码
#include <QThread>
class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);

protected:
    void run();

signals:
    // 自定义信号, 传递数据
    void curNumber(int num);

public slots:
};

子类源文件

cpp 复制代码
#include "mythread.h"
#include <QDebug>
MyThread::MyThread(QObject *parent) : QThread(parent)
{}

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

    int num = 0;
    while(1)
    {
        emit curNumber(num++);
        if(num == 10000000)
        {
            break;
        }
        QThread::usleep(1);
    }
    qDebug() << "run() 执行完毕, 子线程退出...";
}
cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
#include <QDebug>

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

    qDebug() << "主线程对象地址:  " << QThread::currentThread();
    // 创建子线程
    MyThread* subThread = new MyThread;

    connect(subThread, &MyThread::curNumber, this, [=](int num)
    {
        ui->label->setNum(num);
    });

    connect(ui->startBtn, &QPushButton::clicked, this, [=]()
    {
        // 启动子线程
        subThread->start();
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}
相关推荐
大风起兮123 小时前
ESP32,uart安装驱动uart_driver_install函数剖析,以及intr_alloc_flags 参数的意义
开发语言·单片机·嵌入式硬件
不是AI3 小时前
【C语言】【C++】Curl库的安装
c语言·开发语言·c++
NoneCoder3 小时前
JavaScript系列(26)--安全编程实践详解
开发语言·javascript·安全
编程小筑3 小时前
R语言的数据库编程
开发语言·后端·golang
兩尛3 小时前
maven高级(day15)
java·开发语言·maven
大熊程序猿3 小时前
golang 环境变量配置
开发语言·后端·golang
玩电脑的辣条哥4 小时前
如何用python部署本地ocr脚本
开发语言·python·ocr
Ai 编码助手4 小时前
如何使用PHP构建IoC容器,实现依赖注入!
开发语言·rpc·php
宏夏c4 小时前
【Vue】let、const、var的区别、适用场景
开发语言·javascript·ecmascript
贩卖纯净水.4 小时前
JS后盾人--再一次的走进JS?
开发语言·javascript·ecmascript