什么是信号与槽?
通俗理解信号就是发送的某种动作或特征的表现形式。槽就是响应信号的响应动作。
场景一:十字路口信号灯
场景二 PowerPoint按键
-
连接函数:信号与槽的绑定。要考虑发送信号的实例特征与接收信号的实例特征。即
哪个灯,什么动作,哪辆车
这些问题。
-
槽函数:信号的响应动作函数。
- 对应关系:一对多,多对一,多对对,一对一。
信号与槽原理
信号与槽时用于对象之间的通信,是Qt的核心。
信号与槽不是C++标准代码,是QT特有的。会通过MOC
(Mete-Objeci Compiler)进行重新编译为C++。
MOC编译流程
QT程序 |
C++语法文件(MOC得到)+源码C++文件 |
C++编译器 |
二进制文件 |
如何实现信号与槽机制?
实现方式
UI方式
利用控件和信号与槽编辑器。
步骤
新建控件->右键控件(转到槽)->选择信号->编辑槽函数;
新建控件->在信号与槽编辑器中选择发送者,信号,接收者和槽函数。
好处:操作方便
坏处: 看不到连接函数等详细步骤,处理复杂逻辑不适用。
代码方式(QT4)
QObject类:connect和disconnect 连接函数(QT4+QT5使用)
在QObject 类中有一个Public Function为connect函数。
以及Static Public Menbers有大量重载的connect函数。
找到类与类的信号与槽函数(QT4+QT5使用)
如QWidget类,即界面类。
找到他发出的信号与他的槽函数入如下:
举例
connect(ui->pushButton_3,SIGNAL(clicked()),this,SLOT(close()));
解释:
发送方:ui->pushButton_3
发送信号:clicked();
接收对象: this即改界面QWidget类实例。
接收槽函数:close();//退出
总结
好处:信号与槽比较直观
坏处:
使用宏定义时,如果存在错误,在编译阶段不会报错,运行阶段会报错。
运行connect(ui->pushButton_3,SIGNAL(click()),this,SLOT(close()));
clicked变成click就会报错。
使用宏定义时,宏定义里面的参数,不能加参数名,只能加参数类型。
运行connect(ui->pushButton_3,SIGNAL(clicked(bool check )),this,SLOT(close()));
就会报错,改成connect(ui->pushButton_3,SIGNAL(clicked(bool)),this,SLOT(close()));
就可以。
代码方式(QT5)
举例
connect(ui->pushButton_4,&QPushButton::clicked,this,&QWidget::close);
总结
好处:能完美解决QT4的问题
坏处:
信号和槽函数不能传参
解决:自定义槽函数,信号方式(针对QT5不能传参的问题)
改进一:将槽函数入口自定义:(QT4不支持)
connect(ui->pushButton_4,&QPushButton::clicked,this,&QtDesigner::customSlot);
void QtDesigner::customSlot(){
this->close();
}
Lambda方式
connect(ui->pushButton_5,&QPushButton::clicked,this,[=](){
this->close();
});
自定义方式
//自定义
connect(ui->pushButton_6,&QPushButton::clicked,this,[=](){
emit customSignal();//触发信号
}); connect(this,&QtDesigner::customSignal,this,&QtDesigner::customSlot);
void QtDesigner::customSlot(){
this->close();
}
其中ui实例中的定义包含:
signals:
void customSignal(); //仅声名,未定义。
private slots:
void customSlot();
总结自定义信号和槽函数的特征
- 关键字前面不要加访问控制符private,public,protected
- 只需要声名,不需要定义。使用emit激活信号
- 返回类型为void
- 关键字前面要加访问控制符private,public,protected
- 需要声名和定义。
- 返回类型为void
函数指针方式
//函数指针
void(QtDesigner::*closeui)() = &QtDesigner::customSlot;
connect(ui->pushButton_7,&QPushButton::clicked,this,closeui);