大家在使用Qt开发程序时,都知道怎么使用Qt的信号槽,但是Qt信号槽是怎么工作的?大部分人仍然不知道;也就是说大家只知道怎么使用,却不知道基于什么原理,显然这是不符合深层次发展的;那么今天我就给大家基于Qt源码以及示例代码深度剖析Qt的信号槽机制,一定会对大家有帮助。基本概念信号 当对象改变其状态时,信号就由该对象发射(emit)出去,而且对象只负责发送信号,它不知道另一端是谁在接收这个信号。槽 用于接收信号,而且槽只是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。信号与槽的连接QMetaObject::ConnectionQObject::connect(constQObjectsender,constcharsignal,constQObjectreceiver,constcharmethod,Qt::ConnectionTypetypeQt::AutoConnection) 通过QObject::connect静态函数建立连接;其中sender与receiver是指向对象的指针,signal与method分别通过SIGNAL()与SLOT()宏来进行转换。元对象编译器 MOC,theMetaObjectCompiler。 Qt程序在交由标准编译器(例如MSVC)编译之前,先使用moc分析cpp头文件;如果它发现在一个头文件中包含了QOBJECT宏,则会生成另外一个cpp源文件(moc文件名。cpp),该cpp源文件中包含了QOBJECT宏的实现、运行时信息(反射)等。因此Qt程序的完整编译过程为moc预处理编译链接 【领QT开发教程学习资料,点击下方链接莬费领取,先码住不迷路】 点击领取链接示例代码Counter。h文件pragmaonceincludeQtCoreQObjectclassCounter:publicQObject{QOBJECTpublic:Counter();public:intvalue()publicslots:voidsetValue(intvalue);signals:voidvalueChanged(intnewValue);private:};Counter。cpp文件includeCounter。hCounter::Counter():mvalue(0){}intCounter::value()const{}voidCounter::setValue(intvalue){if(value!mvalue){emitvalueChanged(value);}}main。cpp文件includeQtCoreQCoreApplicationincludeCounter。hintmain(intargc,charargv〔〕){QCoreApplicationa(argc,argv);CountercounterA;CountercounterB;QObject::connect(counterA,SIGNAL(valueChanged(int)),counterB,SLOT(setValue(int)));counterA。setValue(10);counterA。value()10,counterB。value()10counterB。setValue(20);counterA。value()10,counterB。value()20returna。exec();}Qt宏 宏定义在qobjectdefs。h文件中(位于QtCore目录)signalsslotsQOBJECTemitSIGNALSLOTQt信号槽的宏使用 宏定义在qobjectdefs。h文件中(位于QtCore目录)signalsdefinesignalsQSIGNALSdefineQSIGNALSpublicQTANNOTATEACCESSSPECIFIER(qtsignal)defineQTANNOTATEACCESSSPECIFIER(x) 推导出来的结果如下,即signals就是publicdefinesignalspublicslotsdefineslotsQSLOTSdefineQSLOTSQTANNOTATEACCESSSPECIFIER(qtslot)defineQTANNOTATEACCESSSPECIFIER(x) 推导出来的结果如下,即slots为空defineslotsQOBJECTdefineQOBJECTpublic:QTWARNINGPUSHQOBJECTNOOVERRIDEWARNINGstaticconstQMetaObjectstaticMetaOvirtualconstQMetaObjectmetaObject()virtualvoidqtmetacast(constchar);virtualintqtmetacall(QMetaObject::Call,int,void);QTTRFUNCTIONSprivate:QOBJECTNOATTRIBUTESWARNINGQDECLHIDDENSTATICMETACALLstaticvoidqtstaticmetacall(QObject,QMetaObject::Call,int,void);QTWARNINGPOPstructQPrivateSignal{};QTANNOTATECLASS(qtqobject,) QOBJECT声明一些函数以及一个静态的QMetaObject对象,这些函数的实现位于MOC所产生的源文件中;因此,这些函数的声明与实现就都有了; 精简版如下所示::defineQOBJECTpublic:staticconstQMetaObjectstaticMetaOvirtualconstQMetaObjectmetaObject()virtualvoidqtmetacast(constchar);virtualintqtmetacall(QMetaObject::Call,int,void);QTTRFUNCTIONSprivate:QDECLHIDDENSTATICMETACALLstaticvoidqtstaticmetacall(QObject,QMetaObject::Call,int,void);emit emit宏为一个空宏;它甚至没有被MOC解析,换句话说,emit只是可选的,没有任何意义(除了给开发人员一个提示)。defineemitSIGNALifndefQTNODEBUGdefineQLOCATIONFILE:QTSTRINGIFY(LINE)defineSIGNAL(a)qFlagLocation(2aQLOCATION)elsedefineSIGNAL(a)2aendifSLOTifndefQTNODEBUGdefineQLOCATIONFILE:QTSTRINGIFY(LINE)defineSLOT(a)qFlagLocation(1aQLOCATION)elsedefineSLOT(a)1aendifQt信号槽宏推导归纳definesignalspublicdefineslotsdefineQOBJECTpublic:staticconstQMetaObjectstaticMetaOvirtualconstQMetaObjectmetaObject()virtualvoidqtmetacast(constchar);virtualintqtmetacall(QMetaObject::Call,int,void);QTTRFUNCTIONSprivate:QDECLHIDDENSTATICMETACALLstaticvoidqtstaticmetacall(QObject,QMetaObject::Call,int,void);defineemitdefineSIGNAL(a)2adefineSLOT(a)1a如何查看预处理之后的代码 在VisualStudio中按如下操作查看预处理之后的代码::右键工程【属性】菜单,弹出属性页对话框依次单击【配置属性】【CC】【预处理器】设置【预处理到文件】选项值为是工程编译 预处理之后代码与初始代码对比 Counter类声明对比 Counter类定义对比 main函数对比 因此,上述分析一目了然,理论推导与实践结果是高度一致的;