Qt 跨UI线程的数据交换和信号-槽调用实现方案汇总
一、目录
转载1: http://my.oschina.NET/fanhuazi/blog/737224?ref=myread 点击打开链接
转载2: http://www.qtcn.org/bbs/read-htm-tid-60505-ds-1-page-1.html#172183 点击打开链接
二、内容
由于以下两篇转载文章都使用了C++11 新特性“lamda表达式”,为了方便同仁阅读以下内容,在此引用一片文章对“C++11 lamda表达式”做一个简要介绍:
“C++11 lamda表达式” ,点击此链接先了解C++11新增语法,对后面内容的阅读会有帮助。
转载1: http://my.oschina.Net/fanhuazi/blog/737224?ref=myread 点击打开链接
在Qt中将函数发送到主线程执行
……(省略部分内容,完成内容请参看上面的原文链接)数据共享的问题,试想“后台线程(非UI线程)中的数据如何能够被前台(UI线程)所使用,而且前台后台不一定在一个类里面?把数据打包通过信号传给前台?”想想就是很麻烦的事情,难道每个这样的需求场合都要做一遍这样的事情吗?感谢时间,因为时间穿过2011年,C++的新标准已经完美的解决了这个问题,那就是函数对象。
Qt的4.8.6版本所使用的mingw4.9.2版本是支持C++11的,如果你用的是老掉牙的rhel5系统,则需要升级编译器了,因为C++11要在GCC 4.5以上的版本中才会支持。
首先我们定义一个类:FunctionTransfer(函数大挪移),这个类继承自QObject,并使用Q_OBJECT标签来使用信号槽机制。代码中的“std::tr1::function<void()>”就是C++标准库中大名鼎鼎的函数对象。
- class FunctionTransfer : public QObject
- {
- Q_OBJECT
- public:
- ///@brief 构造函数
- explicit FunctionTransfer(QObject *parent = 0);
- public:
- ///@brief 制定函数f在main中执行
- static void execinmain(std::tr1::function<void()> f);
- signals:
- ///@brief 在别的线程有函数对象传来
- void comming(std::tr1::function<void()> f);
- public slots:
- ///@brief 执行函数对象
- void exec(std::tr1::function<void()> f);
- };
然后是源文件:
- //在全局数据区实例化一个FunctionTransfer的实例,该实例所在的县城就是主线程。
- FunctionTransfer main_thread_forward;
- void FunctionTransfer::execinmain(std::tr1::function<void()> f)
- {
- main_thread_forward.exec(f);
- }
- FunctionTransfer::FunctionTransfer(QObject *parent) :
- QObject(parent)
- {
- connect(this,SIGNAL(comming(std::tr1::function<void()>)),this,SLOT(exec(std::tr1::function<void()>)),Qt::BlockingQueuedConnection);
- }
- void FunctionTransfer::exec(std::tr1::function<void()> f)
- {
- if(Gt::isMainThread())
- {
- f();
- }
- else
- {
- emit this->comming(f);
- }
- }
非常简单的逻辑,如果在主线程就执行,如果不是在主线程就发给主线程,主线程接到之后就执行。
类有了,接下来考虑实用的场合,比如有一个类 A,A有个方法f不能再后台执行,需要跑到前台,怎么办呢,上代码:
- FunctionTransfer::execinmain([this](){this->f();});
作为参数的lamda表达式捕获了类A的this指针,然后转换为C++的函数对象,然后跑到前台去执行了,执行完成后才会返回,是不是灰常简洁。
转载2:http://www.qtcn.org/bbs/read-htm-tid-60505-ds-1-page-1.html#172183 点击打开链接
- #pragma once
- #include <qthread.h>
- #include <functional>
- class QIoService : QObject
- {
- public:
- QIoService(bool startinthread)
- {
- if(startinthread)
- {
- worker=new QThread(NULL);
- worker->start();
- this->moveToThread(worker);
- }
- else
- {
- //this object is created in create thread!!!
- }
- }
- void post(std::function<void()> func);
- void send(std::function<void()> func);
- void post(std::function<void()> func,int ms);
- void send(std::function<void()> func,int ms);
- virtual bool event ( QEvent * e);
- protected:
- QThread *worker;
- };
- //this should run in mainthread
- extern QIoService *main_ioservice;
- #include "stdafx.h"
- #include "qioservice.h"
- #include <qapplication.h>
- #include <qtconcurrentrun.h>
- QIoService *main_ioservice=NULL;
- class FunctionEvent : public QEvent
- {
- public:
- static const QEvent::Type myType = static_cast<QEvent::Type>(2000);
- FunctionEvent(std::function<void()> f)
- :QEvent(myType)
- {
- func=f;
- }
- ~FunctionEvent()
- {
- //这个他会自动删除
- }
- std::function<void()> func;
- };
- void QIoService::post(std::function<void()> func)
- {
- QApplication::instance()->postEvent(this,new FunctionEvent(func));
- }
- void QIoService::send(std::function<void()> func)
- {
- QApplication::instance()->sendEvent(this,new FunctionEvent(func));
- }
- void QIoService::post(std::function<void()> func,int ms)
- {
- auto lam = [&]()
- {
- QThread::currentThread()->wait(ms);
- post(func);
- };
- QtConcurrent::run(lam);
- }
- void QIoService::send(std::function<void()> func,int ms)
- {
- auto lam = [&]()
- {
- QThread::currentThread()->wait(ms);
- send(func);
- };
- QtConcurrent::run(lam);
- }
- bool QIoService::event ( QEvent * e)
- {
- if(e->type()==FunctionEvent::myType)
- {
- FunctionEvent *fe=(FunctionEvent *)e;
- fe->func();
- return true;
- //这个他会自动删除,不用我们自己手工delete
- }
- return false;
- }
注解:
- //比如你在另外一个线程,你收到数据,想修改界面。就弄个全局变量
- QIoService g_ui_ios(false);
- //你只要
- g_ui_ios.send([你的变量]
- {
- //修改界面数据,这个会在主线程执行
- });
- //如果你是想写个任务队列,
- QIoService g_worker_ios(true);

- //你要把某段事情丢到其他线程执行,就
- g_worker_ios.send([]
- {
- //这段会在其他线程执行。
- 如果执行完了,又想在主线程执行某段,这里可以继续
- //g_ui_ios.send([]
- {
- //这段会在主线程执行
- });
- });
三、更新
2016年8月27日 第一次更新
http://blog.csdn.net/qq2399431200/article/details/52335517
Qt 跨UI线程的数据交换和信号-槽调用实现方案汇总的更多相关文章
- [转]QT子线程与主线程的信号槽通信-亲测可用!
近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI.所以,网络通信端采用新开线程的方式.在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦.网上提供了很多同一线程不同类间采用信号槽 ...
- Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案
本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注.Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调 ...
- Exchanger实现线程间数据交换
package com.duchong.concurrent; import java.util.ArrayList; import java.util.List; import java.util. ...
- 详解 Qt 线程间共享数据(用信号槽方式)
使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...
- Qt学习:线程间共享数据(使用信号槽传递数据,必须提前使用qRegisterMetaType来注册参数的类型)
Qt线程间共享数据主要有两种方式: 使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的: 使用singal/slot机制,把数据 ...
- moveToThread的最简单用法(依葫芦画瓢即可)(使得线程也更偏向于信号槽的使用方法)
/*! * \file main.cpp * * Copyright (C) 2010, dbzhang800 * All rights reserved. * */ #include <QtC ...
- WPF / Win Form:多线程去修改或访问UI线程数据的方法( winform 跨线程访问UI控件 )
WPF:谈谈各种多线程去修改或访问UI线程数据的方法http://www.cnblogs.com/mgen/archive/2012/03/10/2389509.html 子线程非法访问UI线程的数据 ...
- Qt5中运行后台网络读取线程与主UI线程互交
项目中有一个需求就是,因为需要请求服务端数据,因为网络的读取会阻塞,所以该过程不能放在Qt中的UI主线程当中,需要用一个后台线程来读取数据,数据准备完毕后 在通过Qt5中的信号槽机制来跨线程的传递数据 ...
- c#多线程(UI线程,控件显示更新) Invoke和BeginInvoke 区别
如果只是直接使用子线程访问UI控件,直接看内容三,如果想深入了解从内容一看起. 一.Control.Invoke和BeginInvoke方法的区别 先上总结: Control.Invoke 方法 (D ...
随机推荐
- 学习鸟哥的Linux私房菜笔记(16)——Ubuntu中建立ftp服务
1.安装vsftpd,如下图所示:sudo apt-get install vsftpd 2.查看本机是否可以连接ftp 如上图所示,发现login failed了,怎么办呢?我们来看看vsftpd的 ...
- Oracle数据库的基本概念(转)
一.数据库 我们在安装Oracle数据库时,全局数据库名:就是一个数据库的标识,在安装时就要想好,以后一般不修改,修改起来也麻烦,因为数据库一旦安装,数据库名就写进了控制文件,数据库表,很多地方都会用 ...
- iOS中,MRC和ARC混编
假设一个project为MRC,当中要加入ARC的文件: 选择target -> build phases -> compile sources -> 单击ARC的文件将compil ...
- 【codeforces 534D】Handshakes
[题目链接]:http://codeforces.com/contest/534/problem/D [题意] n个人依次进入一个房间; 进进来的人会和房间里面没有组队的人握一次手; (这里的握手只计 ...
- vue-router设置页面标题
通过vue-router设置页面标题 const router = new Router({ routes: [ { path: '/', name: 'EntryConfirmation', met ...
- Python 标准库 —— string
1. maketrans()/translate() maketrans(frm, to) -> string, 建立从字符串 frm 到 to 的映射表(字符串的形式): translate( ...
- 在asp.net core中使用cookie认证
以admin控制器为要认证的控制器举例 1.对控制器设置权限特性 //a 认证命名空间 using Microsoft.AspNetCore.Authorization; using Microsof ...
- Bjarne Stroustrup语录2(一些C++使用注意点)
一.致读者 1. 在编程序时,你是在为你针对某个问题的解决方案中的思想建立起一种具体表示.让程序的结构尽可能地直接反映这些思想: ★.如果你能把“它”看成一个独立的概念,就把它做成一个类. ...
- WPF中的3D特性和常见的几个类
原文:WPF中的3D特性和常见的几个类 WPF 3D 常用的几个类及其关系 1. Visual 类 所有二维可视化元素的基类,为 WPF 中的呈现提供支持,其中包括命中测试.坐标转换和边界 ...
- WPF安装打印机驱动后PrintDialog 执行打印事件
原文:WPF安装打印机驱动后PrintDialog 执行打印事件 WPF可以很好的利用流文档来实现打印预览和PrintDialog 实现打印功能,但是我在这只是写了一个很简单的打印功能演示. Page ...