首页 > 其他分享 >Qt基础之九:子线程和GUI交互

Qt基础之九:子线程和GUI交互

时间:2022-11-20 12:31:57浏览次数:32  
标签:Qt parent int GUI MyThread ui 线程 postEvent MainWindow


首先要强调的是,子线程是不能直接操作GUI的,关于原因,详见:
​​C++面试题之为什么不能多线程直接操作GUI状态​​  
Qt提供了三种方式来实现异步操作GUI
1.postEvent
2.信号和槽
3.InvokeMethod

一.postEvent

[static] void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)
:postEvent函数将事件添加到事件队列后立即返回,receiver是该事件的接收者。事件必须分配到堆上,因为事件队列将获得事件的所有权,并在发布后将其删除。在事件发布后访问它是不安全的。
事件按优先级降序排序,即优先级高的事件在优先级低的事件之前排队。优先级可以是任何整数值,即INT_MAX和INT_MIN之间,包括INT_MAX;有关详细信息,请参阅Qt::EventPriority。
许多第三方库通过回调函数的方式将数据传给上层处理,比如将解码后的图像数据交给Qt渲染显示。但回调函数不一定运行在主线程中,因此我们需要将数据封装成事件,然后用postEvent添加到事件列表,接着就可以在主线程重写的event方法中处理该事件了。

struct Frame
{
uint8_t *buffer;
int width;
int height;
};
// 回调函数.
void FrameNotifyHandler(void *userData, Frame *frame)
{
QHMediaPlayerGL *self = (QHMediaPlayerGL *)userData;
QHFrameEvent::postEvent(self, frame);
}
// 主线程中处理事件.
bool QHMediaPlayerGL::event(QEvent *e)
{
QHFrameEvent *ev = QHFrameEvent::event(e);
if(ev)
{
if(hasPlayMedia())
{
m_videoBuffer=ev->frame()->buffer;
m_videoWidth=ev->frame()->width;
m_videoHeight=ev->frame()->height;
update();
}

return true;
}

return QWidget::event(e);
}

二.信号和槽

常用于将子线程执行结果更新到GUI。下面的例子中将子线程中的累加值更新到按钮上

class MyThread: public QThread
{
Q_OBJECT

public:
explicit MyThread(QObject *parent = nullptr): QThread(parent)
{

}

~MyThread()
{
requestInterruption();
quit();
wait();
}

void run()
{
qDebug() <<"worker thread id=" << QThread::currentThreadId();
static int i = 0;
while(!isInterruptionRequested())
{
sleep(1);
emit update(i++);
}
}

signals:
void update(int value);
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);

qDebug() <<"main thread id=" << QThread::currentThreadId();

MyThread *thread = new MyThread(this);
connect(thread, &MyThread::update, this, [=](int value){
ui->pushButton->setText(QString::number(value));
});

// 处理子线程的finished信号.
connect(thread, &MyThread::finished, []{
qDebug() << "worker thread exit";
});

thread->start();
}

三.InvokeMethod

关于InvokeMethod详见:
​Qt基础之五:使用invokeMethod异步调用函数​​ 

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <QtConcurrent>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
Q_OBJECT

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

private:
Ui::MainWindow *ui;

bool m_running;
QFuture<void> m_future;
};
#endif // MAINWINDOW_H

mainwindow.cpp 

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QThread>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, m_running(true)
{
ui->setupUi(this);
qDebug()<<"main thread id="<<QThread::currentThreadId();

m_future = QtConcurrent::run([&]{
static int i = 0;
qDebug()<<"worker thread id="<<QThread::currentThreadId();
while(m_running)
{
QThread::sleep(1);
QMetaObject::invokeMethod(this, [&]{
ui->pushButton->setText(QString::number(i++));
qDebug()<<"invokeMethod thread id="<<QThread::currentThreadId();

});
}
});
}

MainWindow::~MainWindow()
{
m_running = false;
m_future.waitForFinished();

delete ui;
}

由于使用了并发模块QtConcurrent,需要在 .pro 中添加: QT += concurrent

标签:Qt,parent,int,GUI,MyThread,ui,线程,postEvent,MainWindow
From: https://blog.51cto.com/u_15753490/5871329

相关文章

  • unix网络编程2.2——高并发服务器(二)多进程与多线程实现
    目录前置文章unix网络编程1.1——TCP协议详解(一):https://www.cnblogs.com/kongweisi/p/16882787.htmlunix网络编程2.1——高并发服务器(一)基础——io与文件描述符、socket编......
  • QT入门之创建新窗口
    1.在QT里面新建1个工程,命名01QT,先生成个空的项目。 2 新建1个源文件C++Source文件,命名main.cpp.main 方法里面这样写//主应用程序QApplicationapp(argc,argv);......
  • nove.19 Qtree1(还是树剖)
    https://www.luogu.com.cn/problem/P4114注意在跳重链的时候链顶要考虑(即不能dfn[top[u]]+1,dfn[u])因为跳完一条重链,u=faz[top[u]],此后再跳就没有考虑到链顶与链顶faz的......
  • Vue XQTypeScriptFramework 使用
    说明XQTypeScriptFramework隶属于XQFramework下JS基础性框架部分XQFramework励志将开发将常用开发语音基础性框架统一汇总,为全站开发使用到的基础语法进行统一,拜......
  • 线程间通信
    ---线程由于是在同一个进程中,所以线程间通信使用全局变量进行通信 共享资源:多个线程都可以操作的资源为共享资源,对共享资源的操作代码段称为临界区。对共享资源的无序......
  • 初学linux笔记 第四章 windows中开发的QT程序适配linux的修改——error: ‘QT_WARNING
    QT程序本身在windows中进行开发的,移植到linux系统上进行编译后发现了不少问题,需要一一进行修改1.系统时间修改首先是系统时间问题SYSTEMTIMEcurrent_date_time;GetLo......
  • qt wps
    1过2过3过icon//设置图标statusTip//状态提示shortcut//设置快捷键1过........................................................................
  • 线程(Thread)基本用法
    一.线程的调用1.无参defrun_01():foriinrange(6,10):print("test01",i)time.sleep(1)th_01=threading.Thread(target=run_01)#创......
  • 一招解决错误:This application failed to start because not Qt platform plugin coul
    #遇到的问题最近换了电脑很郁闷,装钉钉装印象笔记打开后,均提示以下这个错误, 错误内容:ThisapplicationfailedtostartbecausenotQtplatformplugincouldbeinit......
  • Python的线程如何理解
    Num01-->多线程threadingPython中建议使用threading模块,而不要使用thread模块。原因如下:1,Python中threading模块对thread进行了一些包装,可以更加方便的使用。2,Python......