Qt中在子线程中刷新UI的方法

Qt中在子线程中刷新UI的方法

在Qt中UI界面并不是线程安全的,意味着在子线程中不能随意操作UI界面组件(比如按钮、标签)等,如果强行操作这些组件有可能会导致程序崩溃。那么在Qt中如何在子线程中刷新UI控件呢?

两种方法:

方法一:使用信号槽机制。

第一步:创建一个QWidget项目,并且在其中添加一个继承自QThread的子线程类QWorkThread,如下:

c++ 复制代码
#ifndef QWORKTHREAD_H
#define QWORKTHREAD_H

#include <QObject>
#include<QThread>


class QWorkThread : public QThread
{
    Q_OBJECT
public:
    explicit QWorkThread(QThread *parent = nullptr);
    QWorkThread(QWidget* pWidget,QThread *parent = nullptr);
    QWidget* m_pWidget = nullptr;

protected:
    virtual void run() override;

signals:
    void UpdateUI(QString strInfo);
};

#endif // QWORKTHREAD_H

说明:

1.自定义一个信号UpdateUI用来刷新主线程UI。

2.重写run函数,使用emit 发射UpdateUI信号如下:

c++ 复制代码
void QWorkThread::run()
{
    emit UpdateUI("刷新控件");
}

第二步:在MainWindow中定义一个槽函数,用来响应UpdateUI信号:

c++ 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

public slots:
    void UpdateWidgetUI(QString strInfo);


private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

第三步:调用connect连接UpdateUI信号和UpdateWidgetUI槽函数,刷新UI:

C++ 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qworkthread.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QWorkThread* pThread = new QWorkThread(ui->label);
    connect(pThread,&QWorkThread::UpdateUI,this,&MainWindow::UpdateWidgetUI);
    connect(pThread,&QThread::finished, pThread, &QThread::deleteLater);
    pThread->start();
}

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

void MainWindow::UpdateWidgetUI(QString strInfo)
{
    ui->label->setText(strInfo);
}

程序运行前后结果:

方法二:使用invokeMethod()方法。

第一步:增加一个带QWidget的构造函数,并且在QWorkThread定义一个QWidget 类型的变量用来保存要刷新的控件。如上QWorkThread头文件中。

第二步:修改QWorkThread::run方法如下:

c++ 复制代码
void QWorkThread::run()
{
    if(m_pWidget != nullptr)
      QMetaObject::invokeMethod(m_pWidget,"setText",Qt::QueuedConnection,Q_ARG(QString,"刷新控件2"));
}

其中调用QMetaObject::invokeMethod方法。

程序运行结果如下:

虽然Qt不允许子线程直接操作UI界面,但通过信号与槽机制或invokeMethod()方法,子线程和UI线程可以安全地进行交互。这些机制确保了多线程程序的稳定性,避免了UI更新时可能出现的线程安全问题。

参考文章:Qt/C++面试【速通笔记五】---子线程与GUI线程安全交互

相关推荐
Larry_Yanan7 小时前
QML学习笔记(四十三)QML与C++交互:上下文属性暴露
c++·笔记·qt·学习·ui·交互
江公望12 小时前
Qt的QT_QPA_EGLFS_INTEGRATION环境变量浅解
linux·qt·qml
精英的英13 小时前
【工具开发】适用于交叉编译环境的QT qmake项目转换vscode项目插件
人工智能·vscode·qt·开源软件
Source.Liu13 小时前
【BuildFlow & 筑流】品牌命名与项目定位说明
c++·qt·rust·markdown·librecad
unicrom_深圳市由你创科技14 小时前
工业上位机,用Python+Qt还是C#+WPF?
python·qt·c#
Larry_Yanan1 天前
QML学习笔记(四十二)QML的MessageDialog
c++·笔记·qt·学习·ui
Main. 241 天前
从0到1学习Qt -- 创建项目
qt
共享家95271 天前
QT-常用控件(多元素控件)
开发语言·前端·qt
寻找华年的锦瑟1 天前
Qt-键鼠事件
开发语言·qt
jjjxxxhhh1231 天前
【项目-】Qt + QCustomPlot 实现频谱监测仪:四图联动、高频信号注入、鼠标交互全解析
开发语言·qt·交互