前言
学以致用,通过QT框架的学习,一边实践,一边探索编程的方方面面.
参考书:<Qt 6 C++开发指南>(以下称"本书"),继承关系沿用本书说法:父类/子类,而非传统C++使用基类/派生类
标识说明:概念用粗体+倾斜.重点内容用(加粗黑体)---重点内容(红字)---重点内容(加粗红字),
本书原话内容用深蓝色标识,比较重要的内容用加粗倾斜下划线深蓝色标识
引入
Qt框架功能是本书的核心内容,本贴展开对信号与槽的理解
简介
本书P28第3段:信号与槽是Qt编程的基础,也是Qt的一大创新.有了信号与槽的编程机制,在Qt中处理界面上各个组件的交互操作就变得比较直观和简单.
---解读:信号与槽的设计思想是让界面上各个组件的交互操作直观和简单.
举个简单的例子:有个对话框,有"确定"和"取消"两个按钮,点击"确定"后执行某个操作(假设打开另一个对话框)并关闭对话框,点击"取消"按钮后不执行其它操作,关闭对话框(图略)
这2个操作由2个信号-槽来完成.其中点击"确定"按钮是一个信号,槽函数是与之对应的确定效果.同理点击"取消"按钮也是一个信号,槽函数是与之对应的取消效果.
信号与槽发生了什么
信号和槽都是函数,发生了数据变化.他们的逻辑是"当信号函数被调用,槽函数被执行".
本书P28第6段:信号与槽关联是用函数QObject::connect()实现的,使用函数connect()的基本格式如下:
QObject::connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));
这是QObject类的静态函数,可以直接调用(非对象调用),而QObject是大部分Qt类的基类,所以可以直接写成
connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));
sender是发射信号的对象的名称;signal是信号,信号可以看作特殊的函数,需要带有括号,有参数时还需要指明各参数类型;receiver是接收信号的对象的名称;slot是槽函数,需要带有括号,有参数时还需要指明各参数类型.SIGNAL和SLOT是Qt的宏,分别用于指明信号和槽函数.
信号与槽的使用规则
1.一个信号可以连接多个槽函数
---表示:一个因多个果
2.多个信号可以连接同一个槽函数
---表示多个因指向一个果
3.一个信号可以连接另一个信号
---表示一个因指向另一个因
4.严格情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数.如果参数不匹配,会出现编译错误或运行错误.
---笔者不理解划线部分,信号参数个数和槽参数个数有关系?
5.在使用信号与槽的类中,必须在类的定义中插入宏Q_OBJECT
6.当一个信号被发射时,与其关联的槽函数通常被立即运行,就像正常调用函数一样.只有当信号关联的所有槽函数运行完毕后,才运行发射信号处后面的代码.
其他
信号与槽的操作是比较简单的,但是本书示例的代码P29~P31,以及P53~P57部分不是太好读,要和后面的具体类相结合,同时信号与槽在后面应用十分广泛,所以这部分内容在后面的章节用到时再做理解.
信号与槽的底层机制分析
有了前面对元数据和元对象的理解,尝试理解信号与槽的实现.
=============================内容分割线↓===================================
以下内容属于作者发散思考,不保证对错.
方案一
信号与槽的逻辑联系:当信号对象的方法被调用,随即调用槽对象的函数.假设有一个类专门处理信号与槽
/*伪代码*/
struct Signal_Slot{
QObject sender;
QMetaMethod sd_qm;
QObject receiver;
QMetaMethod rv_qm;
}
程序中可以定义多个connect函数,每定义一个connect函数,生成一个Signal_Slot对象,并把信号对象和槽对象的元数据---对象类型,方法名称,参数等信息传入.建立一个信号与槽的集合
vector<Signal_Slot> vss;
1>程序运行时,有一个函数进行状态采集---程序反复运行,一直扫描和采集.扫描内容是输入和焦点对象,输入一般是鼠标和键盘,例如鼠标左键点击/右键点击,键盘按下了某个键;焦点对象是笔者自己给的定义,例如鼠标正移动到某个对象上,或者键盘用tab键指向的对象;比如"点击OK键",需要同时满足"鼠标移动到了OK键上"和"鼠标左键点击"的判定.输入和焦点对象被记录下来进入2>.焦点对象的采集,需要比对鼠标位置(位置)和对象所在位置(坐标).
2>根据扫描的状态---实际上是查找信号函数(可能有可能没有),遍历vss,如果遍历到有数据存在---说明信号函数和槽函数都有定义,则执行槽函数.
这种思路需要元数据的支持,可能还需要对编译器做修改.
方案二
直接connect函数的定义表达,这需要满足几个条件:
有一个类型能代表所有类型对象,
有一个函数指针能指向所有类型函数;
类型和函数指针合在一起能表示对象方法.
前面的状态采集和查找仍需要
=============================内容分割线↑===================================
小结
信号与槽函数的简单理解