近用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 = ); 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();
}

自己定义的类继承了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 = );
~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 = );
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 = ;
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 = );
~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线程发送消息通知界面小例

[转]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. SVN多项目并行版本管理解决方案

    1.背景 随着公司业务拓展,各业务部门频繁的需求变更,导致系统集成冲突的问题日益突出. 2.现状 基于SVN版本管理模式,多分支版本并行,分支合并主干交付.多分支开发存在依赖关系且有交付的先后顺序, ...

  2. Linux常用基本命令:三剑客命令之-awk动作用法(1)

    1,多个动作,怎么写? ghostwu@dev:~/linux/awk$ cat host.txt name ip地址 host1 192.168.1.1 host2 192.177.81.1 hos ...

  3. WordPress 新版本中编辑器不好用, 使用原有编辑器

    将以下代码添加到当前主题的函数模板 functions.php 文件中即可. add_filter('use_block_editor_for_post', '__return_false'); re ...

  4. python之正则表达式及RE模块

    正则表达式(匹配字符串)web界面正则匹配工具:http://tool.chinaz.com/regex/ 元字符 1 . 匹配除换行符之外的任意字符 2 \w 匹配数字字母下划线 3 \d 匹配数字 ...

  5. 谈谈web上各种图片应用的优缺点

    web中承载信息的主要方式就是图片与文字了,以下就是对一些web图片格式的优缺点进行归纳. 1.GIF GIF图是比较古老的web图片格式之一,可以追溯到1987,几乎所有的浏览器都支持这一种格式,老 ...

  6. Stackoverflow 珠玑:用于分组的 LINQ 扩展方法

    从 stackoverflow.com 上抄来的,将 IEnumerable 中的元素进行切分的方法,无动态内存分配,地球上最快的实现: public static class LinqExtensi ...

  7. flask中的url_for的使用

    有多个路由的程序需要连接不同的网页链接,例如导航条 模板中构建正确的动态url较为困难,如果重定义路由,模板中的链接失效 url_for()函数: 使用url映射中保存的信息生成url 用法: 用视图 ...

  8. MySQL写入用户微信名

    很简单的需求,将用户微信名写入MySQl即可,但是测试过程中却遇到了问题,微信名中的emoji写入数据库失败.解决步骤如下 1.了解utf8mb4 MySQL从5.5.3版本开始支持utf8mb4编码 ...

  9. 关于Natively Compiled Stored Procedures的优化

    Interpreted Transact-SQL stored procedures are compiled at first execution, in contrast to natively ...

  10. Sql Server 增加字段、修改字段、修改类型、修改默认值

    1.修改字段名: alter table 表名 rename column A to B 2.修改字段类型: alter table 表名 alter column 字段名 type not null ...