最近用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
9. {  
10.     Q_OBJECT  
11. public:  
12. explicit
13.   
14. protected:  
15. void
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
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
9. class
10. }  
11.   
12. class MainWindow : public
13. {  
14.     Q_OBJECT  
15.   
16. public:  
17. explicit
18.     ~MainWindow();  
19.   
20. private
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. new
7. {  
8. this);  
9.   
10. //进行connect前必须实例化
11. new
12.   
13. int)), this, SLOT(DisplayMsg(int)));  
14.   
15. //执行子线程
16.     t->start();   
17. }  
18.   
19. void MainWindow::DisplayMsg(int
20. {  
21.     ui->textBrowser->append(QString::number(a));  
22. }  
23.   
24. MainWindow::~MainWindow()  
25. {  
26. delete
27. }



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


运行效果

python qt线程之间传递数据 qt 线程间传递消息_qt开发


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


testthread.h 文件

1. #ifndef TESTTHREAD_H
2. #define TESTTHREAD_H
3.   
4. #include <QThread>
5.   
6. #include "msg.h"
7.   
8. class TestThread : public
9. {  
10.     Q_OBJECT  
11. public:  
12. explicit
13.     Msg msg;  
14.   
15. protected:  
16. void
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
9. {  
10.     msg.int_info = 999;  
11. "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
10. class
11. }  
12.   
13. class MainWindow : public
14. {  
15.     Q_OBJECT  
16.   
17. public:  
18. explicit
19.     ~MainWindow();  
20.   
21. private
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. new
7. {  
8. this);  
9.   
10. //进行connect前必须实例化
11. new
12.   
13. //Msg!!!
14. this, SLOT(DisplayMsg(Msg)));  
15.   
16. //执行子线程
17.     t->start();  
18. }  
19.   
20. void
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
29. }



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


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



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


mainwindow.cpp文件 改动为



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



    此时能够正常运行

    python qt线程之间传递数据 qt 线程间传递消息_线程_02



    说明:

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

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

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



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

    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)));
    //除了注册结构体外  还要保证传递的参数写法要一样  这就是为什么 前面线程自己定义的结构体自己调用自己的原因了