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

首先我们看看一般的方式:
利用信号-槽发送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 QThread
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit TestThread(QObject *parent = );
  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();
  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 = );
  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 = );
  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 = ;
  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 = );
  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类的构造方法进行改造。mainwindow.cpp文件改动(蓝色加粗部分)为:

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

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

结论:

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

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

参考链接:

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

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

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

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

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

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

[转]QT子线程与主线程的信号槽通信-亲测可用!的更多相关文章

  1. Qt自己定义事件实现及子线程向主线程传送事件消息

    近期在又一次学习Qt的时候,由于要涉及到子线程与主线程传递消息,所以便琢磨了一下.顺便把有用的记录下来,方便自己以后查询及各位同仁的參考! 特此声明,本篇博文主要讲述有用的,也就是直接说明怎么实现,就 ...

  2. WinForm 中使用 Action 子线程对主线程 控制进行访问

    /// <summary> /// 开启新线程执行 /// </summary> /// <param name="sender"></p ...

  3. c# 子线程与主线程通信二

    之前写过使用线程上下文实现线程同步,今天利用子线程向主线程发送事件,实现子线程与主线程的同步 基本步骤 1.定义类 using System; using System.Collections.Gen ...

  4. 19 Handler 子线程向主线程发送信息

    案例一 Message创建三种方法: package com.example.day19_handler_demo1; import android.os.Bundle; import android ...

  5. C# 子线程与主线程通讯方法一

    最近在项目中要用到子线程运行结束向主线程通知的需求,利用线程上下文来实现线程之间的同步. 子线程结束后调用同步函数,向主线程发送时间字符串,改变主窗体的label标签 label标签改变事件触发处理函 ...

  6. Android笔记(三十一)Android中线程之间的通信(三)子线程给主线程发送消息

    先看简单示例:点击按钮,2s之后,TextView改变内容. package cn.lixyz.handlertest; import android.app.Activity; import and ...

  7. C# 子线程调用主线程窗体的解决方法

    摘自其他人博客,自己试过确实解决问题.(如在自己定义的线程里面给textbox赋值) 由于Windows窗体控件本质上不是线程安全的.因此如果有两个或多个线程适度操作某一控件的状态(set value ...

  8. Android中,子线程使用主线程中的组件出现问题的解决方法

    Android中,主线程中的组件,不能被子线程调用,否则就会出现异常. 这里所使用的方法就是利用Handler类中的Callback(),接受线程中的Message类发来的消息,然后把所要在线程中执行 ...

  9. Unity3d 创建线程 子线程与主线程通信

    创建子线程 一,不带参数 Thread   resourcesLoadThread=new Thread (this.resourceLoadTxt); resourcesLoadThread.Sta ...

随机推荐

  1. Memcached部署和用法

    一.Memcached简介 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网 ...

  2. Maven远程仓库的各种配置

    1.远程仓库的配置 在平时的开发中,我们往往不会使用默认的中央仓库,默认的中央仓库访问的速度比较慢,访问的人或许很多,有时候也无法满足我们项目的需求,可能项目需要的某些构件中央仓库中是没有的,而在其他 ...

  3. 如何在UWP中统一处理不同设备间的页面回退逻辑

    已经有一段时间没有写博客来记录自己的学习点滴了.现在回想起来确实有些惭愧,期间经历了一些事情,到目前为止算是平息了,是时候该收收心来充实自己了. 在本篇缪文中,楼主打算给UWP开发的初学者讲述一个在开 ...

  4. JavaScript函数箭头的优势在哪里

    译者按: 看上去只是语法的变动,其实也影响了this的作用域. 原文: JavaScript: Arrow Functions for Beginners 译者: Fundebug 为了保证可读性,本 ...

  5. Excel破解工作表保护

    宏运行 Public Sub Password_cracking() Const DBLSPACE As String = vbNewLine & vbNewLine Const AUTHOR ...

  6. 【代码笔记】Web-HTML-脚本

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  7. 《Inside C#》笔记(十三) 多线程 上

    通过将一个任务划分成多个任务分别在独立的线程执行可以更有效地利用处理器资源并节省时间.但如果不合理地使用多线程,反而会带来种种问题并拖慢运行速度. 一 线程基础 a)线程与多任务 一个线程就是一个处理 ...

  8. angularjs的$http请求方式

    /*$http常用的几个参数 $http服务的设置对象: 1.method 字符串 表示发送的请求类型 get post jsonp等等 2.url 字符串 绝对或者相对的URL,请求的目标 3.pa ...

  9. 安装mysql(macos系统)

    1.到官网下载,直接百度"mysql"即可找到 2.双击安装包,一路安装即可 3.然后进到系统设置 4.接下来 输入coho的用户密码 设置root用户的密码 切换root用户,v ...

  10. 命令行选项 - Mozilla 产品与私有技术 | MDN - Google Chrome

    命令行选项 在本文章中 语法规则 使用命令行选项 示例 用户配置档 -CreateProfile profile_name -CreateProfile "profile_name prof ...