QT子线程与主线程的信号槽通信

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


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


testthread.h 文件

[cpp] view plaincopy
print?
  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文件

[cpp] view plaincopy
print?
  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

[cpp] view plaincopy
print?
  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

[cpp] view plaincopy
print?
  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 文件

[cpp] view plaincopy
print?
  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 文件

[cpp] view plaincopy
print?
  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 文件

[cpp] view plaincopy
print?
  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 文件

[cpp] view plaincopy
print?
  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会有提示

[cpp] view plaincopy
print?
  1. QObject::connect: Cannot queue arguments of type 'Msg'  
  2. (Make sure 'Msg' is registered using qRegisterMetaType().)  

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


mainwindow.cpp文件 改动为

[cpp] view plaincopy
print?
  1. ui->setupUi(this);  
  2.   
  3. qRegisterMetaType<Msg>("Msg");  

此时能够正常运行




说明:

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383260.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++中的函数适配器

函数适配器 函数适配器概念 STL中定义了大量的函数对象&#xff0c;但是有时候需要对函数返回值进行进一步的简单计算&#xff0c;或者填上多余的参数&#xff0c;不能直接代入算法&#xff0c;函数适配器实现了这一功能&#xff0c;将一种函数对象转化为另一种符合要求的函数…

c++中STL实现演讲比赛流程

演讲比赛流程 1&#xff09;某市举行一场演讲比赛&#xff0c;共有 24 个人参加&#xff0c;按参加顺序设置参赛号。比赛共三轮&#xff0c;前两 轮为淘汰赛&#xff0c;第三轮为决赛。 2&#xff09;比赛方式&#xff1a;分组比赛 第一轮分为 4 个小组&#xff0c;根据参赛号…

c++实现贪吃蛇

游戏中的实现元素 游戏中元素分为&#xff1a;墙壁&#xff0c;蛇&#xff0c;事物以及蛇的可行区域和右侧的版本号和游戏玩法提示 墙壁 *号表示&#xff0c;代表一个区域范围&#xff0c;也就是蛇的可移动区域&#xff0c;蛇如果碰到墙壁视为死亡&#xff0c; 蛇 分为蛇头&a…

Linux系统编程--1(进程和程序,CPU和MMU,PCB,进程状态)

进程相关概念 程序和进程 程序&#xff1a;是指编译好的二进制文件&#xff0c;在磁盘上&#xff0c;不占用系统资源(cpu、内存、打开的文件、设备、锁…) 进程&#xff1a;是一个抽象的概念&#xff0c;与操作系统原理联系紧密。进程是活跃的程序&#xff08;程序员角度&…

Linux系统编程--2(环境变量,进程控制)

环境变量 环境变量 是指在操作系统中用来指定操作系统运行环境的一些参数 每个人用电脑的习惯不一样&#xff0c;比如一般把文件放到磁盘&#xff0c;怎么管理文件&#xff0c;用什么编译器&#xff0c;所以&#xff0c;环境变量就是根据每个人使用操作系统的习惯来规定一些参…

套接字编程--1(UDP协议编程,端口号,传输层协议,网络字节序)

传输层的协议&#xff1a; ip地址&#xff1a; 在网络中唯一标识一台主机 IPV4&#xff1a;uint32_t DHCP NATIPV6 : uint8_t addr[16] —向前并不兼容IPV4 每一条数据都必须包含源地址和目的地址&#xff1a;因为每条网络中的数据都必须确定是从那个主机来到那个主机去 端…

Linux系统编程--3(exec 函数族,僵尸进程和孤儿进程,wait和wait_pid回收子进程)

exec 函数族 fork 创建子进程后执行的是和父进程相同的程序&#xff08;但有可能执行不同的代码分支&#xff09; &#xff0c;子进程往往要调用一种 exec 函数以执行另一个程序。当进程调用一种 exec 函数时&#xff0c;该进程的用户空间代码和数据完全被新程序替换&#xff…

交换机MAC地址学习和转发数据帧的原理

1 &#xff1a;交换机 MAC 地址学习在交换机初始化的&#xff0c;也就是刚启动的时候&#xff0c;交换机的MAC地址表是没有任何MAC地址和端口的映射条目的 当PCA要想和PCC&#xff0c;PCB,PCD进行通信时&#xff0c;当该二层数据帧通过端口E1/0/1发送到交换机上时&#xff0c…

Linux系统编程---4(进程间通信IPC,管道)

进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间共享同样的资源。通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了某种事件&#xff08;如进…

冲突域 广播域简单解释

网络互连设备可以将网络划分为不同的冲突域、广播域。但是&#xff0c;由于不同的网络互连设备可能工作在OSI模型的不同层次上。因此&#xff0c;它们划分冲突域、广播域的效果也就各不相同。如中继器工作在物理层&#xff0c;网桥和交换机工作在数据链路层&#xff0c;路由器工…

Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)

共享存储映射 文件进程间通信 使用文件也可以完成 IPC&#xff0c;理论依据是&#xff0c;fork 后&#xff0c;父子进程共享文件描述符。也就共享打开的文件。 编程&#xff1a;父子进程共享打开的文件。借助文件进行进程间通信。 测试代码 /*** 父子进程共享打开的文件描述…

变量的存取

一、预备知识―程序的内存分配 一个由c/C编译的程序占用的内存分为以下几个部分 1、栈区&#xff08;stack&#xff09;― 由编译器自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区&#xff08;heap&#xff…

Linux系统编程---6(信号的机制,信号4要素,Linu常规信号表,定时器)

信号的概念 信号在我们的生活中随处可见&#xff0c; 如&#xff1a;古代战争中摔杯为号&#xff1b;现代战争中的信号弹&#xff1b;体育比赛中使用的信号枪… 他们都有共性&#xff1a; 简单不能携带大量信息&#xff0c;只能带一个标志。满足某个特设条件才发送。 Unix 早…

Linux系统编程----7(信号集,信号屏蔽,信号捕捉)

信号集操作函数 内核通过读取未决信号集来判断信号是否应被处理。信号屏蔽字 mask 可以影响未决信号集。而我们可以在应 用程序中自定义 set 来改变 mask。已达到屏蔽指定信号的目的。 信号集设定 sigset_t set; //typedef unsigned long sigset_t;int sigemptyset(sigset_t…

Linux系统编程---8(全局变量异步I/O,可重入函数)

全局变量异步 I/O 分析如下父子进程交替 数数 程序。当捕捉函数里面的 sleep 取消&#xff0c;程序即会出现问题。请分析原因。 #include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h>intn0,flag0; void sys_err(char* s…

http使用post上传文件时,请求头和主体信息总结

请求头必须配置如下行&#xff1a; Content-Type : multipart/form-data; boundary---12321 boundary---12321位文件的分界线 body如下&#xff1a; "-----12321\r\n" //分割文件时加-- "Content-Disposition: form-data; name\"…

Linu系统编程---9(SIGCHLD 信号,信号传参,中断系统调用)

SIGCHLD 信号 SIGCHLD 的产生条件 子进程终止时子进程接收到 SIGSTOP 信号停止时子进程处在停止态&#xff0c;接受到 SIGCONT 后唤醒时 借助 SIGCHLD 信号回收子进程 子进程结束运行&#xff0c;其父进程会收到 SIGCHLD 信号。该信号的默认处理动作是忽略。可以捕捉该信号…

Linu系统编程---10(Linux的终端,线路规程,网络终端,进程组)

终端 输入输出设备的总称 在 UNIX 系统中&#xff0c;用户通过终端登录系统后得到一个 Shell 进程&#xff0c;这个终端成为 Shell 进程的控制终端&#xff08;Controlling Terminal&#xff09;&#xff0c; 进程中&#xff0c;控制终端是保存在 PCB 中的信息&#xff0c;而 …

Linux系统编程---11(会话,守护进程,创建守护进程)

会话 创建会话 创建一个会话需要注意以下6点注意事项 调用进程不能是进程组组长&#xff0c;该进程变成新会话首进程该进程成为一个新进程组的组长进程需要root权限&#xff08;nbuntu不需要&#xff09;新会话丢弃原有的控制终端&#xff0c;该会话没有控制终端该调用进程是…