Qt_log2000_信号与槽中的connect函数之深入part2
来源:互联网 发布:淘宝学校哪家好 编辑:程序博客网 时间:2024/06/04 00:24
Qt学习记录6 (5’)
Qt; C++ 11; Qt父子窗体; Qt父子窗体间信息传递; Qt信号与槽; 函数指针;
学习Qt将近2个月了,现在对学习所得进行记录。本文是log2000计划的一部分
实验环境:
Qt5.8.0 支持C++ 11
ubuntu 14.04 64bit
现在看一下Qt中的signal,这是C++里面没有的东西
假设有一个A类和一个B类,A类发射信号,定义如下(选择在a.h中没在a.cpp中定义)
#ifndef A_H#define A_H#include <QObject>class A : public QObject{ Q_OBJECTsignals://定义一个信号//应该是个成员函数指针,只是被Qt简化为这种无形参无返回值的形式 void signal();public: void useSignal(){//使用信号 emit signal();//emit时Qt会帮你调用signal所指向的槽函数,可以只想别的类的函数,如B类 }};#endif // A_H
B类接收信号,定义如下(选择在b.h中没在b.cpp中定义)
#ifndef B_H#define B_H#include <QObject>#include <iostream>using namespace std;class B : public QObject{ Q_OBJECTpublic: void fun() { //定义一个“槽” cout<<"接受对象a的信号,运行对象b的函数。"<<endl; }};#endif // B_H
- signals应该是个成员函数指针,只是被Qt简化为这种无形参无返回值的形式
emit signal();
时Qt会帮你调用signal所指向的槽函数,可以只想别的类的函数,如B类
将A类的信号与B类的函数连接起来,(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)这个过程,这个框架,就是图形界面的一大核心
main函数
#include "a.h"#include "b.h"int main(int argc, char *argv[]){ A a; B b; //连接信号和槽 QObject::connect(&a,&A::signal, &b,&B::fun); //使用信号 a.useSignal(); return 0;}
- connect中的
&B::fun
一定是个类成员函数的指针,signal
既然要跟B类的fun函数连接起来,要“对等”,signal本身一定也是一个成员函数的指针,但由于signal和A本身就是分开写的,(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)所以必须用这种&A::signal
成员变量指针的形式写这个signal
下面试一试我们自己写出connect的函数,自己把A类的一个信号和B类的一个函数连接起来。
“解开”
#include <iostream>using namespace std;//第四步才看class A;class B;typedef void (A::*Apointer)();typedef void (B::*Bpointer)();//第一步开始看class A { public: void (A::*click)();//给A类定义了成员变量click,类型为成员函数指针类型,click理论上等于onClicked() void onClicked(){ cout<<"按A上面的按钮,调用了自己的onClick函数!"<<endl; } //第四步才看 B* slotObj; void TreatClickEvent(){ (slotObj->*(Bpointer)click)(); }};//第三步才看class B { public: int x=5; void onClicked(){ cout<<"按A上面的按钮,调用了B的onClick函数! 成员变量x的值为"<<x<<endl; }};//第一步开始看:复习成员变量指针void runMemberVariblePointer(A * obj, int A::* pMember) { cout<<obj->*pMember<<endl;}//第一步开始看:复习成员函数指针void runfuncName(A * obj, void (A::*func)()){ (obj->*func)();}//第一步看:组合成员变量指针和成员函数指针void runfuncPointer(A * obj, void (A::*( A::*pfunc ))()){ //Apointer A::* pfunc (obj->*(obj->*pfunc))();}//typedef void (A::*Apointer)();//第二步才看//typedef void (A::*(A::*Signal))();typedef Apointer A::* Signal;void connect(A* a, Signal signal, Apointer slot){ //void (A::*slot)() a->*signal = slot;}//第三步才看void connect(A* a, Signal signal, Bpointer slot){ a->*signal = (Apointer) slot;}//第四步才看void connect(A* a, Signal signal, B* b, Bpointer slot){ a->*signal = (Apointer) slot; a->slotObj = b;}int main(int argc, char *argv[]){ //第一步、理解信号的本质:成员函数指针类型的特殊成员变量 //第二步、连接A本身的信号与槽 A a; runfuncName(&a,&A::onClicked); connect(&a,&A::click,&A::onClicked);//a.click = &A::onClicked; (a.*a.click)(); runfuncPointer(&a,&A::click); //第三步:连接A的信号到B的槽 B b; B * fb = &b; connect(&a, &A::click, &B::onClicked);//a.click = (void (A::*)())&B::onClicked; (a.*a.click)(); (b.*(Bpointer)a.click)();//(fb->*(Bpointer)a.click)(); //第四步:完善连接A的信号到B的槽 connect(&a, &A::click, fb, &B::onClicked); a.TreatClickEvent(); return 0;}
运行结果
Starting /home/pc/build-testmyConnect-Desktop_Qt_5_8_0_GCC_64bit-Debug/testmyConnect...按A上面的按钮,调用了自己的onClick函数!按A上面的按钮,调用了自己的onClick函数!按A上面的按钮,调用了自己的onClick函数!按A上面的按钮,调用了B的onClick函数! 成员变量x的值为4197508按A上面的按钮,调用了B的onClick函数! 成员变量x的值为5按A上面的按钮,调用了B的onClick函数! 成员变量x的值为5/home/pc/build-testmyConnect-Desktop_Qt_5_8_0_GCC_64bit-Debug/testmyConnect exited with code 0
看到:
runMemberVariblePointer
函数:int A::* pMember
,是成员变量指针,实际上就是普通指针加上一个A::
runfuncName
函数:void (A::*func)()
,是成员函数指针,实际上就是普通函数指针加上一个A::
runfuncPointer
函数:void (A::*( A::*pfunc ))()
,从外层看,是成员函数指针void(A::* ~ )
。从内层看,A::*pfunc
,这个是成员变量指针的定义。如果使用typedef,将第四步提前看一下,typedef void (A::*Apointer)();
这个就是使用typedef定义的普通A类成员函数定义法,Apointer就是成员函数指针类型的类型名。于是刚才的void (A::*( A::*pfunc ))()
是可以换为Apointer A::* pfunc;
的,是等价的。Apointer A::* pfunc;
这个形式就与runMemberVariblePointer
函数中的int A::* pMember
形式完全一样了。- 现在
runfuncPointer
函数参数的写法看懂了,接下来看怎么调用。(obj->*(obj->*pfunc))();
中obj这个对象出现了2次,首先要通过这个obj把第一个A::*
“解开”,也就是obj->*pfunc
把内层A::*pfunc
部分“解开”,接着还需“解开”外面的一层,因为外层本身就是A类的成员函数指针类型,所以使用(obj->*(~))();
解开它。 - 接下来看main函数如何运行,首先调用
runfuncName
,通过a对象调用A类的onClicked,对应上面函数定义的(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)成员函数指针类型,通过成员函数指针的方式调用onClicked。输出了第一行【按A上面的按钮,调用了自己的onClick函数!】接下来使用了connect,把a传进去,把A::click传进去,把A::onClicked传进去,把A类的一个signal连接到一个A类的slot,实现了a.click = &A::onClicked; - main函数中
(a.*a.click)();
调用click,a.click就是成员变量,因为这个成员变量是个成员变量指针,所以要加个*,然后再前面加上“对象.” - 到第二步处看connect函数的定义,在前面加了typedef简化语法,signal就相当于之前的pfunc类型,槽slot的类型就是成员函数指针类型。connect实际上就是把信号的成员变量指针那一层解开,剩下成员函数指针,直接与slot相连
a->*signal = slot;
与(obj->*(obj->*pfunc))();
比较,slot相当于外面这一层,a->*signal相当于解开里层,于是剩下外层的signa可以直接与slot做“=” - signal实际上就是一个成员函数指针类型,只不过信号写到connect函数里面当参数的时候connect必须要把它跟对象分开为两个参数,所以才又套了一层成员变量指针。
typedef Apointer A::* Signal;
使用Apointer简化signal,写typedef语句,使用Apointer来定义signal语句,对应typedef void (A::*(A::*Signal))();
处就可改为typedef Apointer A::signal;
接下来扩展,A类的click要指向B类的onClicked。看第三步。
- void connect(A* a, Signal signal, Bpointer slot)中,a->*signal = (Apointer) slot;强制类型转换,把slot转为A类型,再赋给A类的signal,输出了【按A上面的按钮,调用了B的onClick函数! 成员变量x的值为4197508】,x的值并不是5,说明虽然调用的B类的onClicked函数,但传递的this指针不对,是a的this指针。
- 于是还需要传入b的和this指针。于是强制转为b的指针
(b.*(Bpointer)a.click)();
相当于执行(fb->*(Bpointer)a.click)();
现在输出的是【按A上面的按钮,调用了B的onClick函数! 成员变量x的值为5】
但这么连接A的信号与B的函数还是太麻烦,于是看到第四步
void connect(A* a, Signal signal, B* b, Bpointer slot)
,a和b对象地址都传进去了。传进去之后首先还是a->*signal = (Apointer) slot;
需要强转因为是slot不是Apointer类型,然后a->slotObj = b;
看到A类定义里面的第四步,有一个B* slotObj;
- A类中的
TreatClickEvent()
定义模拟的是emit signal - 最后main函数中将他们连接起来
connect(&a, &A::click,fb, &B::onClicked);a.TreatClickEvent();
这样与Qt中的写法就一致了。最后输出最后一句【按A上面的按钮,调用了B的onClick函数! 成员变量x的值为5】
小挑战:
实现任意两个类的连接,如何?
提示:
引入继承结构和虚函数,onclick如果是虚函数会方便一点。继承结构是保证B* slotObj;
可以只想任何其他类型,把B变成父类或者在AB上新建一个共同的父类。(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)还有就是在connect里面使用模板。这样真正实现Qt中的connect,但Qt中的connect前提也是类都必须继承QObject。QObject做得就是signal和emit的工作。
visitor tracker
- Qt_log2000_信号与槽中的connect函数之深入part2
- Qt_log2000_信号与槽中的connect函数之深入part1
- Qt_log2000_父子窗体传递数据-使用信号与槽
- qt中的connect()函数 信号槽
- QT 信号与槽 connect函数
- 信号与槽的connect连接函数
- 信号与槽,connect
- Qt中connect函数(信号与槽)初识
- QT中的信号-槽函数与多线程
- QT中Connect函数 信号槽
- QT信号与槽之槽函数
- Qt信号与槽之connectSlotsByName函数
- 深入了解信号与槽
- Qt中的信号和槽之connect----多线程调用全解析(同步/异步)
- Qt中的信号和槽之connect----多线程调用全解析(同步/异步)
- 深入探究connect函数
- 深入探究connect函数
- 深入探究connect函数
- 第3课 01 JS中级课程-焦点事件-1
- HTML5 App 跨域请求 携带cookie
- spark mllib之Extracting, transforming and selecting fea
- ajax的三种实现方式及解释json数据
- PHP中的接口
- Qt_log2000_信号与槽中的connect函数之深入part2
- 单例模式(c++实现)
- tensorflow的共享变量,tf.Variable(),tf.get_variable(),tf.Variable_scope(),tf.name_scope()联系与区别
- Python笔记
- linux下编译netcat并且反弹cmdshell
- rails视图层
- 一道网易数据分析题的R解法
- POJ 3237 树链剖分+数据结构维护 题解
- Tensorflow新版Seq2Seq接口使用