在QT中实现GUI主线程与耗时操作的分离(后台执行耗时计算时窗口不会阻塞卡住)

1.前言

在QT开发时,对于耗时的操作经常会出现窗口阻塞的情况,这个时候如果再频繁操作窗口,可能会导致窗口崩溃。造成这个问题的关键原因是在QT中GUI是作为主线程存在的,比如我们执行一个点击按钮的操作,主线程需要等待槽函数执行结束后才能继续响应,这就导致了窗口的阻塞。搜索相关的内容大多的解决方法都提到使用QThread多线程的方法,这种方法我也测试过的确可以解决,但是使用起来比较复杂,往往需要重写类。尽管moveToThread方法能够灵活一些,也需要将耗时的操作另写入一个类中,还是比较复杂。经实践发现使用QtConcurrent::run能够更简单一些(如果需求仅仅是将GUI线程与数据操作线程分离开)。

2.QtConcurrent

Qt Concurrent 是QT中用于并发编程的框架,可以简化多线程编程,特别是对于简单的并行任务。Qt Concurrent 提供了一些类和函数,例如 QtConcurrent::run,可以方便地在后台线程中执行函数。如果使用camke构建的项目,在cmakelist文件中只需添加如下代码就可引用这个框架。

find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Core Concurrent)
……
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::Concurrent)

在使用Concurrent实现将 GUI 和数据计算过程分离时,不需要另外再写一个类,只需要将数据操作的耗时任务单独写入一个函数中,然使用 Qt Concurrent 在后台线程中执行该任务就可以。废话不多说直接上示例代码:

mainwindows.h

#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();

signals:
    void worker_pushButton_clicked( int N);    // 触发任务的信号,带参数

public slots:
    void worker_pushButton_finished(int N);    // 耗时任务

private slots:
    void on_actionStart_clicked();             // 按钮点击的槽函数(看具体需求,也可以直接通过按钮信号触发耗时任务) 

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

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "utils.h"
#include <matio.h>
#include <iostream>
#include <fstream>
#include <QThread>
#include <QtConcurrent>


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

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

// 按钮点击槽函数
void MainWindow::on_actionStart_clicked()
{
    connect(this, &MainWindow::worker_pushButton_clicked, [&](int N) {
        QtConcurrent::run(this, &MainWindow::worker_pushButton_finished, N);
        });
    emit worker_pushButton_clicked(100);
}

//耗时任务槽函数
void MainWindow::worker_pushButton_finished(int n)
{
    int Sum = 0;
    for (int i = 0; i < n; i++)
    {
        Sum += i;
        QThread::sleep(1);
        ui->lineEdit->setText(QString::number(Sum));
    }
}

在上面的代码中我是通过qtdesigner设计了窗口,添加了一个pushbutton和一个lineEdit,在点击按钮后将触发任务的信号与任务的槽函数绑定并使用QtConrurrent::run将任务放入线程中并行,而后触发信号。

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt窗口线程通信是指在Qt程序窗口所在的线程与其它线程通信的过程。Qt程序通常会包含多个线程,而窗口往往位于线程要负责界面的更新和用户输入响应等任务。如果其它线程需要与窗口进行通信,便需要进行线程间通信(Inter-Thread Communication)。 Qt提供了多种线程间通信的方式,其包括信号槽机制、事件机制和共享对象等,这些机制都可用于线程与其它线程之间的通信。其,信号槽机制是最常用的一种方式。线程可以在窗口定义信号(Signal),其它线程可以在需要通知窗口触发该信号,线程则通过槽(Slot)来接收信号并执行相应的操作。此外,也可以通过发送事件的方式来通信,其它线程可以通过调用窗口的postEvent()函数来发送事件,线程则通过重载窗口的event()函数来接收事件并执行相应的操作。 为了确保线程安全,Qt提供了QMutex和QReadWriteLock等线程锁(Thread-Safe Mechanisms),可以在多线程读写共享资源保护数据的一致性,避免出现数据并发访问的问题。在使用这些机制,需要注意不要在线程执行耗时操作,以免阻塞GUI界面的更新,导致程序“假死”。 综上所述,Qt窗口线程通信是一种重要的线程间通信方式,通过合理使用信号槽机制、事件机制和线程锁等工具,可以实现线程和其它线程之间的高效通信,提高程序的运行效率和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值