• [转]QT子线程与主线程的信号槽通信-亲测可用!


      近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI。所以,网络通信端采用新开线程的方式。在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦。网上提供了很多同一线程不同类间采用信号槽通信的方式,但是并不完全适合线程间的信号槽通信,这主要体现在自定义消息的传递上。

    首先我们看看一般的方式:
    利用信号-槽发送Qt内置的元数据类型
    testthread.h 文件

    #ifndef TESTTHREAD_H
    #define TESTTHREAD_H
     
    #include <QThread>
     
    #include "msg.h"
     
    class TestThread : public QThread
    {
        Q_OBJECT
    public:
        explicit TestThread(QObject *parent = 0);
     
    protected:
        void run();
     
    signals:
        void TestSignal(int);
     
    private:
        Msg msg;
    };
     
    #endif // TESTTHREAD_H

    testthread.cpp文件

    #include "testthread.h"
     
    TestThread::TestThread(QObject *parent) :
        QThread(parent)
    {
    }
     
    void TestThread::run()
    {
        //触发信号
        emit TestSignal(123);
    }

    自己定义的类继承了QThread类,重写run函数,然后触发TestSignal信号。

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
     
    #include <QMainWindow>
     
    #include "testthread.h"
     
    namespace Ui {
    class MainWindow;
    }
     
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
     
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
     
    private slots:
        void DisplayMsg(int);
     
    private:
        Ui::MainWindow *ui;
        TestThread *t;
    };
     
    #endif // MAINWINDOW_H

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
     
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
     
        //进行connect前必须实例化
        t = new TestThread();   
     
        connect(t, SIGNAL(TestSignal(int)), this, SLOT(DisplayMsg(int)));
     
        //执行子线程
        t->start(); 
    }
     
    void MainWindow::DisplayMsg(int a)
    {
        ui->textBrowser->append(QString::number(a));
    }
     
    MainWindow::~MainWindow()
    {
        delete ui;
    }

    Mainwindow里面连接信号槽,并且将收到的int参数显示在界面上。

    运行效果:

    利用信号-槽发送自定义消息

    下面我们对程序进行一些简单,修改,使得它传输我们的自定义消息。

    testthread.h 文件

    #ifndef TESTTHREAD_H
    #define TESTTHREAD_H
     
    #include <QThread>
     
    #include "msg.h"
     
    class TestThread : public QThread
    {
        Q_OBJECT
    public:
        explicit TestThread(QObject *parent = 0);
        Msg msg;
     
    protected:
        void run();
     
    signals:
        void TestSignal(Msg);   //Msg!!!
    };
     
    #endif // TESTTHREAD_H

    testthread.h 文件

    #include "testthread.h"
     
    TestThread::TestThread(QObject *parent) :
        QThread(parent)
    {
    }
     
    void TestThread::run()
    {
        msg.int_info = 999;
        msg.str_info = "Hello Main Thread!";
        //触发信号
        emit TestSignal(msg);
    }

    mainwindow.h 文件

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
     
    #include <QMainWindow>
     
    #include "testthread.h"
    #include "msg.h"
     
    namespace Ui {
    class MainWindow;
    }
     
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
     
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
     
    private slots:
        void DisplayMsg(Msg);   //Msg!!!
     
    private:
        Ui::MainWindow *ui;
        TestThread *t;
    };
     
    #endif // MAINWINDOW_H

    mainwindow.cpp 文件

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
     
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
     
        //进行connect前必须实例化
        t = new TestThread();
     
        //Msg!!!
        connect(t, SIGNAL(TestSignal(Msg)), this, SLOT(DisplayMsg(Msg)));
     
        //执行子线程
        t->start();
    }
     
    void MainWindow::DisplayMsg(Msg msg)
    {
        ui->textBrowser->append(QString::number(msg.int_info));
        ui->textBrowser->append(msg.str_info);
    }
     
    MainWindow::~MainWindow()
    {
        delete ui;
    }

    此时再进行编译,能够通过,但是Qt Creator会有提示

    QObject::connect: Cannot queue arguments of type 'Msg'
    (Make sure 'Msg' is registered using qRegisterMetaType().)

    并且运行程序,不会有任何反应。需要对mainwindow类的构造方法进行改造。mainwindow.cpp文件改动(蓝色加粗部分)为:

    //以上代码省略
    ui->setupUi(this); qRegisterMetaType<Msg>("Msg");
    //以下代码省略

    此时能够正常运行。以上测试用例,经过本人亲测可用!!!!

    结论:

    (1)在线程间使用信号槽进行通信时,需要注意必须使用元数据类型,Qt内生的元数据类型,如int double QString 等。

    (2)如果要用自己定义的数据类型,需要在connect前将其注册为元数据类型。形式见代码。

    参考链接:

    1、QT子线程与主线程的信号槽通信-(重点参考)

    2、Qt子线程如何更新UI,完整的代码示例,有图有真相-(重点参考)

    3、QT其他线程和UI主线程通信方式

    4、Qt5中运行后台网络读取线程与主UI线程互交

    5、QT小例子GUI(主)线程与子线程之间的通信-子线程和主线程互相发送信号

    6、QT线程发送消息通知界面小例

  • 相关阅读:
    APP排查内存泄漏最简单和直观的方法
    Unable to resolve service for type 'Microsoft.AspNetCore.ResponseCompression.IResponseCompressionProvider' while attempting to activate 'Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMid
    c# json序列化不包括某列
    log4net按级别写到不同文件
    .NETCore_项目启动设置域名以及端口
    Oracle_本地计算机上的OracleOraDb11g_home1TNSListener 服务启动后停止
    Oracle_其他人连接不上自己电脑
    Oracle_创建自增
    Oracle_12541错误和ora-12514错误
    Oracle_PLSQL导出导入dmp文件
  • 原文地址:https://www.cnblogs.com/rainbow70626/p/10332219.html
Copyright © 2020-2023  润新知