关闭

qt线程通信(通过信号触发来传递参数)

标签: qt开发线程通信qt学习socket
58人阅读 评论(0) 收藏 举报
分类:
最近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI。所以,网络通信端采用新开线程的方式。在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦。网上提供了很多同一线程不同类间采用信号槽通信的方式,但是并不完全适合线程间的信号槽通信,这主要体现在自定义消息的传递上。


首先我们看看一般的方式:


testthread.h 文件

  1. #ifndef TESTTHREAD_H  
  2. #define TESTTHREAD_H  
  3.   
  4. #include <QThread>  
  5.   
  6. #include "msg.h"  
  7.   
  8. class TestThread : public QThread  
  9. {  
  10.     Q_OBJECT  
  11. public:  
  12.     explicit TestThread(QObject *parent = 0);  
  13.   
  14. protected:  
  15.     void run();  
  16.   
  17. signals:  
  18.     void TestSignal(int);  
  19.   
  20. private:  
  21.     Msg msg;  
  22. };  
  23.   
  24. #endif // TESTTHREAD_H  

testthread.cpp文件
  1. #include "testthread.h"  
  2.   
  3. TestThread::TestThread(QObject *parent) :  
  4.     QThread(parent)  
  5. {  
  6. }  
  7.   
  8. void TestThread::run()  
  9. {  
  10.     //触发信号  
  11.     emit TestSignal(123);  
  12. }  


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

mainwindow.h

  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.   
  4. #include <QMainWindow>  
  5.   
  6. #include "testthread.h"  
  7.   
  8. namespace Ui {  
  9. class MainWindow;  
  10. }  
  11.   
  12. class MainWindow : public QMainWindow  
  13. {  
  14.     Q_OBJECT  
  15.   
  16. public:  
  17.     explicit MainWindow(QWidget *parent = 0);  
  18.     ~MainWindow();  
  19.   
  20. private slots:  
  21.     void DisplayMsg(int);  
  22.   
  23. private:  
  24.     Ui::MainWindow *ui;  
  25.     TestThread *t;  
  26. };  
  27.   
  28. #endif // MAINWINDOW_H  

mainwindow.cpp
  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3.   
  4. MainWindow::MainWindow(QWidget *parent) :  
  5.     QMainWindow(parent),  
  6.     ui(new Ui::MainWindow)  
  7. {  
  8.     ui->setupUi(this);  
  9.   
  10.     //进行connect前必须实例化  
  11.     t = new TestThread();     
  12.   
  13.     connect(t, SIGNAL(TestSignal(int)), this, SLOT(DisplayMsg(int)));  
  14.   
  15.     //执行子线程  
  16.     t->start();   
  17. }  
  18.   
  19. void MainWindow::DisplayMsg(int a)  
  20. {  
  21.     ui->textBrowser->append(QString::number(a));  
  22. }  
  23.   
  24. MainWindow::~MainWindow()  
  25. {  
  26.     delete ui;  
  27. }  

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


运行效果



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


testthread.h 文件

  1. #ifndef TESTTHREAD_H  
  2. #define TESTTHREAD_H  
  3.   
  4. #include <QThread>  
  5.   
  6. #include "msg.h"  
  7.   
  8. class TestThread : public QThread  
  9. {  
  10.     Q_OBJECT  
  11. public:  
  12.     explicit TestThread(QObject *parent = 0);  
  13.     Msg msg;  
  14.   
  15. protected:  
  16.     void run();  
  17.   
  18. signals:  
  19.     void TestSignal(Msg);   //Msg!!!  
  20. };  
  21.   
  22. #endif // TESTTHREAD_H  

testthread.h 文件
  1. #include "testthread.h"  
  2.   
  3. TestThread::TestThread(QObject *parent) :  
  4.     QThread(parent)  
  5. {  
  6. }  
  7.   
  8. void TestThread::run()  
  9. {  
  10.     msg.int_info = 999;  
  11.     msg.str_info = "Hello Main Thread!";  
  12.     //触发信号  
  13.     emit TestSignal(msg);  
  14. }  

mainwindow.h 文件

  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.   
  4. #include <QMainWindow>  
  5.   
  6. #include "testthread.h"  
  7. #include "msg.h"  
  8.   
  9. namespace Ui {  
  10. class MainWindow;  
  11. }  
  12.   
  13. class MainWindow : public QMainWindow  
  14. {  
  15.     Q_OBJECT  
  16.   
  17. public:  
  18.     explicit MainWindow(QWidget *parent = 0);  
  19.     ~MainWindow();  
  20.   
  21. private slots:  
  22.     void DisplayMsg(Msg);   //Msg!!!  
  23.   
  24. private:  
  25.     Ui::MainWindow *ui;  
  26.     TestThread *t;  
  27. };  
  28.   
  29. #endif // MAINWINDOW_H  

mainwindow.cpp 文件
  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3.   
  4. MainWindow::MainWindow(QWidget *parent) :  
  5.     QMainWindow(parent),  
  6.     ui(new Ui::MainWindow)  
  7. {  
  8.     ui->setupUi(this);  
  9.   
  10.     //进行connect前必须实例化  
  11.     t = new TestThread();  
  12.   
  13.     //Msg!!!  
  14.     connect(t, SIGNAL(TestSignal(Msg)), this, SLOT(DisplayMsg(Msg)));  
  15.   
  16.     //执行子线程  
  17.     t->start();  
  18. }  
  19.   
  20. void MainWindow::DisplayMsg(Msg msg)  
  21. {  
  22.     ui->textBrowser->append(QString::number(msg.int_info));  
  23.     ui->textBrowser->append(msg.str_info);  
  24. }  
  25.   
  26. MainWindow::~MainWindow()  
  27. {  
  28.     delete ui;  
  29. }  

此时再进行编译,能够通过,但是Qt Creator会有提示
  1. QObject::connect: Cannot queue arguments of type 'Msg'  
  2. (Make sure 'Msg' is registered using qRegisterMetaType().)  

并且运行程序,不会有任何反应。


mainwindow.cpp文件 改动为

  1. ui->setupUi(this);  
  2.   
  3. qRegisterMetaType<Msg>("Msg");  

此时能够正常运行




说明:

在线程间使用信号槽进行通信时,需要注意必须使用元数据类型

Qt内生的元数据类型,如int double QString 等

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


转载来自blog.csdn.net/jmy5945hh/article/details/34796359/ 


这个例子是主线程和子线程的,子线程与子线程之间通信呢?

connect 的 第一个参数 和第三个参数改成监听对象

 connect(t, SIGNAL(TestSignal(Msg)), this, SLOT(DisplayMsg(Msg)));


 

以上的this就是主线程响应,把this改成要监听的另一个线程对象就好了(QT多么健壮 友好  强大)

前提是全部的线程都要在主线程里面实例化new


今天实现的一个结构提参数通过Singal传递的例子。。 那个实现是子线程与GUI子线程的参数进行传递  通过mainWindow来做中转。具体是把用户输入的数据进行复杂计算,计算交给线程做,GUI负责用户输入输出


线程头文件

ABFThread.h


public:

    struct G_ABFTableSrcUnit
    {
        int a;
        int b;
        int c;
        float d;
        float e;
        unsigned int f;
        float Gg;
    
        QString waveformTypel;
    };

public slots:

    void parameterPassing(abfThread::G_ABFTableSrcUnit); //线程自己调用自己的结构体。。。必须这么写不然主线程会报错的  错误是参数内容不一样

ABFThread.cpp

void abfThread::parameterPassing(abfThread::G_ABFTableSrcUnit)
{

}

GUI线程

radarControl.h

#include "abfThread"

private:
    Ui::radarControl *ui;

    abfThread::G_ABFTableSrcUnit mst_abfSrcUnit;


signals:
    void sendString(abfThread::G_ABFTableSrcUnit);


radarControl.cpp

按下按钮就发射信号

void radarControl::on_pushButton_clicked()
{
    emit sendString(mst_abfSrcUnit);
}

mainWindow.h

#include "abfThread.h"
#include "radarControl.h"


mainWindow.cpp


radarInterface = new radarControl();
m_ABFThread = new QThread();
    m_ABF = new abfThread();
    m_ABF->moveToThread(m_ABFThread);
    m_ABFThread->start();

    qRegisterMetaType<abfThread::G_ABFTableSrcUnit>("abfThread::G_ABFTableSrcUnit");
    connect(radarInterface,SIGNAL(sendString(abfThread::G_ABFTableSrcUnit)),m_ABF,SLOT(parameterPassing(abfThread::G_ABFTableSrcUnit)));
//除了注册结构体外  还要保证传递的参数写法要一样  这就是为什么 前面线程自己定义的结构体自己调用自己的原因了






0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:655次
    • 积分:99
    • 等级:
    • 排名:千里之外
    • 原创:9篇
    • 转载:4篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档