Qt-信号/槽(single/slot)机制
目录(?)[-]
- 目的对象之间的交互机制
- 方法
- 1 回调函数
- 2 信号槽
- 信号槽详解
- 1 目标将一个类的事件向其它发送并使用相关类可以处理这种事件
- 2 原理信号-槽机制-自动化的回调函数
- 21信号-槽
- 3 信号的连接
- 31连接到槽
- 32连接到其它信号
- 33连接动作响应
- 34自动连接机制
- 35断开连接disconnect
- 351 应用手动创建部件并使用自动连接不推荐
- 4 获取信号的发送对象 QObject QObjectsender const
- 5 获取信号的接收者数量 int QObjectreceivers const char signal const
- 6 阻止信号发送 boolQObjectblockSignals bool block
- 7 多线程的信号-槽安全问题
- 71信号-槽连接方式
- 72多线程中信号-槽交互信号映射
- 8信号-槽与事件的关系
- 信号映射QSignalMapper
Qt-信号/槽(single/slot)机制
sf2gis@163.com
2015年1月6日
2015年3月28日添加信号映射
2015年3月29日添加断开连接
1 目的:对象之间的交互机制。
2 方法
2.1 回调函数
在信号/槽机制之前,一般使用回调函数进行交互。但是这种方式有两个基本的问题:一是类型安全问题,函数对象无明确类型。二是高度耦合,回调函数必须被明确包含在处理函数中。
2.2 信号/槽
信号和槽进行连接后,调用信号就会调用槽。由于信号和槽都是成员函数,是类型安全的。默认情况下也是线程安全的,如果指定了类型,可能降级为类型安全。
信号和槽是完全无关的,使用connect连接才能建立联系,并且槽函数可以忽略信号的参数,两者之间是松散耦合的。
因此,在使用时要注意信号-槽之间的解耦。
3 信号/槽详解
3.1 目标:将一个类的事件向其它发送,并使用相关类可以处理这种事件。
3.2 原理:信号-槽机制-自动化的回调函数。
在执行时,qmake会调用MOC(metaObject compiler)工具,将QObject相关的类重新生成一个新的类MOC_xxx.cpp/h,这时,将所有信号转换为相应的回调函数(槽函数),发出信号就会调用槽函数(参见QObject.cpp->QMetaObject::activate())。
参考 http://woboq.com/blog/how-qt-signals-slots-work.html
http://stackoverflow.com/questions/14080484/qt-signals-and-slot-thread-safety
3.2.1信号-槽
信号与槽技术是Troll Tech公司独立创建的技术。使用MOC(meta object compiler)创建合乎C++标准的回调函数。
信号是特殊的成员函数,只有声明无实体。emit关键字是可选标记。signal/slot也是标记。
Q_OBJECT也是用于标记的宏,只有声明此宏,才会进行信号槽的解析。
signal信号:代表事件,包含用户事件,内部状态事件。使用成员函数实现。
发射信号:emit(可选)。
slot槽:处理事件。标准函数+添加slot标志。
connect连接:将signal与slot进行connect,这样在emitsignal时就调用slot。
QSignalMapper实现信号-槽的连接,只能int,const QString&,QObject *,QWidget*可以作为参数。
注意:只有继承QObject,并且在类的起始声明Q_OBJECT宏,才能使用信号/槽。
方法:
3.3 信号的连接
注意:连接时,只能使用它们的签名,而不应该带有参数名,否则也会出错。
注意:如果连接到当前的槽,则可能省略receiver,但并不推荐这么做,会引起混淆。
3.3.1连接到槽
槽函数可以接收信号传递的参数,也可接收少于信号的参数;
连接:connect(signalObject,signal,slotObject,slot);
断开连接:disconnect(singalObject,signal,slotObject,slot);
3.3.2连接到其它信号
连接:connect(signalObject,signal,signal,signal);
3.3.3连接动作响应
可以自定义连接时动作:connectNotify(),disconnectNotify()
QLatin1String 和 SIGNAL()可以判断信号类型。
重写此虚函数,可以指定在连接某个信号时的动作。
示例:
if (QLatin1String(signal) == SIGNAL(valueChanged(int))) {
// signal isvalueChanged(int)
}
3.3.4自动连接机制
MOC具有自动连接机制,可以根据指定的命名方式,将ui文件中控件的信号和槽进行连接。因此,只有在setupUI()函数之前定义的具有ObjectName的对象,才有可能被自动连接。
注意:自动连接只能应用于QObject与其子对象之间。
自动连接命令方式:void on_<object name>_<signalname>(<signal parameters>);
MOC在ui文件的setupUi()函数中使用QMetaObject::connectSlotsByName(this)函数完成这一功能。
示例:
以下槽函数将自动连接到okButton的clicked信号上。
private slots:
voidon_okButton_clicked();
3.3.5断开连接:disconnect
如果信号或槽的对象释放,则此连接自动删除。
3.3.5.1 应用:手动创建部件,并使用自动连接。(不推荐)。
手动创建部件必须在setupUI()函数执行之前定义,并且设置ObjectName,才能被MOC进行自动连接。注意:创建完成后使用setParent()才能将对象放入指定的父控件。
示例:
QPushButton *pMyBtn = new QPushButton(this);
pMyBtn->setText ("this is my btn");
pMyBtn->setObjectName ("pushButton_8");
pMyBtn->show ();
ui->setupUi(this);
pMyBtn->setParent (ui->centralWidget);
3.4 获取信号的发送对象 QObject* QObject::sender () const
可以获取QObject* 类型的发送对象;将获取的指针进行相应的转化,就可以得知发送对象的详细信息,如whatsThis(),objectName()...;
示例:
qDebug()<<((QPushButton*)(sender()))->objectName();
3.5 获取信号的接收者数量 int QObject::receivers ( const char * signal ) const
用于获取信号的接收者数目。注意:是protected成员。
示例:
connect(this,SIGNAL(transRoutePoint(const QString &,const QString &, const QString &)),this,SLOT(zoomInMap()));
receivers(SIGNAL(transRoutePoint(const QString &, constQString &, const QString &)));//==1;
3.6 阻止信号发送 boolQObject::blockSignals ( bool block )
如果block==true;那么由这个对象发送的信号不会引起任何响应(destroyed()信号除外);
bool QObject::signalsBlocked () const
可以获取当前对象的信号阻止状态;
示例:
m_pPlaneAirline->blockSignals(true);//m_pPlaneAirline发送的信号不会被响应
qDebug()<<"signalcount:"<<m_pPlaneAirline->signalsBlocked();//返回true
3.7 多线程的信号-槽安全问题
3.7.1信号-槽连接方式
多数类都是可以重入的,但不是线程安全的。因此,QT类都应当只在一个线程中使用。因为每个线程都有自己的事件循环。
在多线程中,槽函数的执行是在发送信号的线程中还是在执行槽函数的线程中有完全不同的表现。因此QT给出了连接选项,以指定执行线程。
Qt::DirectConnection,表示直接连接,发送信号后直接执行槽函数,在发送信号线程执行。
Qt::QueuedConnection,表示顺序连接,发送信号后送入队列,只有回到槽函数所在的线程后,再顺序执行。只有将控制权转换到响应线程时才会作出响应,也就是说,如果发送信号线程一直工作,就无法将控制权转换到响应线程。只有发送线程sleep()之后,响应线程才有可能(但不一定)得到控制权。
Qt::BlockingQueuedConnection:与QueuedConnection相似,但每次信号执行会阻塞当前线程,等待slot返回。有可能导致死锁。
Qt::AutoConnection:默认值,单线程时,使用DirectConnection;多线程时,使用QueuedConnection。
Qt::UniqueConnection:与AutoConnection相似,但会清除重复的连接(对于一个线程调用另一个线程中的对象发送信号这种错误应用的容错处理)。
Qt::AutoCompatConnection:兼容QT3。
因此,如果发送者和接收者不在同一个线程,则直接连接是不安全的。
调用其它线程中对象的函数,都是不安全的。
每一个信号的对象,在发出时所在的线程,会有一个信号对象放入信号队列。在多个线程中,使用同一个对象,每个线程中保留源对象的一个副本,然后线程返回主线程时,发送一次信号,则每个线程实际发送了所有线程的信号。
示例:
// DirectConnection,直接执行,所以执行是连贯的
Debugging starts
1 f isStarted? true
sum is running... 1
1 runing...
1 task finished.
sum is finished. 1
2 f isStarted? true
sum is running... 2
2 runing...
2 task finished.
2 task finished.
sum is running... 3
3 f isStarted? true
sum is finished. 2
3 task finished.
3 runing...
3 task finished.
3 task finished.
sum is finished. 3
Debugging has finished
// QueuedConnection,接收者线程执行,所以执行是不连贯的
Debugging starts
1 f isStarted? true
sum is running... 1
1 runing...
sum is finished. 1
2 f isStarted? true
2 runing...
sum is running... 2
sum is finished. 2
sum is running... 3
3 f isStarted? true
3 runing...
sum is finished. 3
1 task finished.
2 task finished.
2 task finished.
2 task finished.
3 task finished.
3 task finished.
3 task finished.
Debugging has finished
3.7.2多线程中信号-槽交互:信号映射
目标:槽函数读取信号发送方的信息。
方法:信号映射。
不能在槽函数的执行线程中需要读取发送线程的对象信息,这是不安全的。如果发送对象已经释放,将无法读取数据。
如果信号是无参数的,可以使用QSignalMapper映射信号,将相关数据发送。参见:信号映射:QSignalMapper。
如果信号是有参数的,应该构造相关的映射类发送数据。
示例:将QProcess的信号映射为带有ID和相应信息的信号
//mapper定义
class QProcessMapper:publicQObject
{
Q_OBJECT
public:
QProcessMapper(const QString&strID,QObject *parent=NULL):
QObject(parent),
m_strID(strID)
{}
signals:
void started(const QString &strID);
void finished(const QString &strID,intiExitCode);
void readyReadStandardOutput(const QString&strID,const QString &strRst);
public slots:
void handleStarted(){emit started(m_strID);}
void handleFinished(int iExitCode){emitfinished (m_strID,iExitCode);}
void handleReadyRead(){emitreadyReadStandardOutput (m_strID,((QProcess*)sender())->readAll ());}
private:
QString m_strID;
};
//mapper 映射
QProcessMapper mapper(strID);
connect(&mapper,SIGNAL(started(QString)),pHandler,SLOT(handleStarted(QString)));
connect(&mapper,SIGNAL(finished(QString,int)),pHandler,SLOT(handleFinished(QString,int)));
connect(&mapper,SIGNAL(readyReadStandardOutput(QString,QString)),pHandler,SLOT(handleReadyRead(QString,QString)));
QProcess process;
connect(&process,SIGNAL(started()),&mapper,SLOT(handleStarted()));
connect(&process,SIGNAL(finished(int)),&mapper,SLOT(handleFinished(int)));
connect(&process,SIGNAL(readyReadStandardOutput()),&mapper,SLOT(handleReadyRead()));
3.8信号-槽与事件的关系
参见:QT特性-QObjectMOS元对象系统SignalSlot信号槽.docx事件系统部分。
4 信号映射:QSignalMapper
目标:将多个无参数的信号连接映射器,由映射器指定参数并重新发送。
使用映射器:将映射器的mapped()信号与需要的槽函数连接。
signalMapper= new QSignalMapper(this);
connect(button,SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button,QString(”myButton”));
connect(signalMapper, SIGNAL(mapped(QString)),this, SIGNAL(clicked(QString)));
转自:http://blog.csdn.net/sf2gis2/article/details/45392693
Qt-信号/槽(single/slot)机制相关推荐
- Qt信号槽机制-传递自定义数据类型(qRegisterMetaType)
Qt信号槽机制-传递自定义数据类型qRegisterMetaType 前言 前言 通过Qt内置的数据类型进行信号与槽参数传递很方便:如果是自己定义的类型如果想使用signal/slot来传递的话,则没 ...
- Hello Qt——Qt信号槽机制源码解析
基于Qt4.8.6版本 一.信号槽机制的原理 1.信号槽简介 信号槽是观察者模式的一种实现,特性如下: A.一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知: B.一个槽就是一个观察 ...
- QT中的Singal\slot机制
QT中的Singal\slot机制 在QT工程项目中,会使用到多窗口或者二级窗口,而窗口之间做数据交流时,可以使用信号\槽机制,将两个不相关的对象相连,达到数据传输的效果. 语法 Connect函数 ...
- Qt信号槽如何传递参数
Qt信号槽如何传递参数 利用Qt进行程序开发时,有时需要信号-槽来完成参数传递.带参数的信号-槽在使用时,有几点需要注意的地方,下面结合实例进行介绍. 1. 当信号与槽函数的参数数量相同时,它们参数类 ...
- Qt信号槽机制详解及案例
目录 信号槽 标准信号槽 自定义信号槽 信号槽 信号槽是Qt框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signa ...
- 深入理解Qt信号槽机制
1. 信号和槽概述 > 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式(发布-订阅模式).当某个`事件`发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(s ...
- c++实现Qt信号槽机制
信号槽机制的原理 信号槽是观察者模式的一种实现,或者说是一种升华: 一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知: 一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候-- ...
- c++模拟qt信号槽机制
qt的信号槽原理:moc元对象编译器翻译头文件成moc文件,实现头文件中的信号的函数体和申明信号.槽的索引,加上一个qt_static_metacall的函数等等,然后在connect中的QObjec ...
- Qt信号槽中connect五个重载函数详细说明,连接类型Qt::DirectConnection,Qt::QueuedConnection,附详细代码
想说在前面的两句话. 信号槽是 Qt 框架引以为豪的机制之一.熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的程序设计能力. 信号与槽是Qt学习的重点,但不是难点. 本篇介绍Qt ...
- 13.QT信号槽的连接方式
QT的信号槽机制和线程的启动方式已经在前面的文章中写过了,本文主要是对信号槽的连接方式进行解读,信号槽的连接方式一共有5种: 1.Qt::DirectConnection 发出信号后立即调用槽函数. ...
最新文章
- 面向对象和基于对象的区别
- cmd mysql_CMD命令操作MySql数据库的方法详解
- 初次树莓派遇到的一些小问题
- 【企业管理】优秀的管理者没有追随者,而是与大家一起奋斗
- java swing 关闭_Java Swing 只关闭当前窗体的实现
- Spark-Serialization序列化的2种方式解释对比使用场景
- SQL server无法打开项 UNKNOWN\Components\929B2416EC4102B48A989956983ACF45\1F7B2B09C788E7644A0F08CA9C1D解决办法
- break;continue语句
- 30年历史回顾,Jeff Dean:我们整理了一份「稀疏专家模型」研究综述
- 湖北省2021年高考成绩查询日期,湖北2021年高考查分及志愿填报时间公布!
- 百度网盘html资源,百度网盘目录索引搭建教程:如何把百度网盘文件做成在线html目录...
- vuex中的actions
- Python实现行业轮动量化选股【附完整源码】
- pytorch张量相乘matmul函数
- html如何把图片在背景图一半,img只显示图片一部分 或 css设置背景图片只显示图片指定区域...
- 2.横切易拉罐(PS)
- 牛客网 KY11 二叉树遍历
- 映射本地ip,实现远程访问教程
- berserkJS 使用 Wind.js 保证序顺执行流程
- 25 岁做什么,可在 5 年后受益匪浅?