1.信号与槽概述
信号与槽用于两个对象之间的通信,为了实现对象间的通信,一些工具包中使用了回调机制(CallBack),而Qt使用信号与槽,这是Qt的核心特征,也是Qt不同于其他开发框架的最突出特征。当一个特殊的事情发生时便可以发射一个信号,比如单击按钮就发射clicked()信号;而槽就是一个函数,它在信号发射后被调用来响应这个信号。
优点
- 信号与槽机制是Qt的核心特征,也是Qt不同于其他开发框架最突出的特征;
- 信号和槽的机制是类型安全的,相对于回调机制,类型不安全,无法保证回调调用参数正确;
- 松散耦合,信号发送者不知也不需要知道接收者的信息;
- 信号和槽可以使用任意类型任意数量的参数。
2.信号、槽
- 信号只需要声明,无需也不能定义,需要使用emit发射信号;槽既要声明,也要定义。
- 自定义的信号可以发生重载,(可以有参数),在发生重载时,要使用函数指针明确一个函数地址,告知使用哪个重载版本。槽在发生重载时也一样,语法如下:
void (域::*指针名)(参数列表) = &域::函数名(重载);
- 信号可以连接信号,可以连接多个槽,当信号发生时,执行顺序将与连接顺序一致。
- 多个信号也可以连接同一个槽函数(例如多个按钮都能关闭窗口)
- 信号和槽函数的参数必须一一对应,包括位置、顺序。
- 信号参数的个数可以多于槽函数的个数,多余的参数将被忽略。
- 信号的声明需要**signals:**关键字,槽函数声明可以使用(public、protected、private)+slots,也可以不使用slots关键字。
- 信号必须是void类型,没有返回值。
- 需要继承自QObject或其子类才可以使用信号与槽机制。
- 在类声明的最开始处添加Q_OBJECT宏,这个一般会自动生成。
3.connect函数
函数原型
connect(信号发送者(对象),信号,信号接收者(对象),槽函数,连接机制);
//如:
connect(btn,&QPushButton::clicked,this,&QWidget::close());
参数5(连接机制)的使用说明
常量 | 描述 |
---|---|
Qt::AutoConnection | 自动关联,默认值、如果信号与槽处于同一个线程,那么使用Qt::DirectConnection,否则使用Qt::QueuedConnection |
Qt::DirectConnection | 发射完信号立即调用槽,只有槽执行完成返回后,发射信号处后面的代码才可以执行(二者在同一线程) |
Qt::QueuedConnection | 队列关联,当控制权返回槽所在线程的事件循环后再执行槽,无论槽执行与否,发射信号之后的代码立即执行 |
Qt::BlockingQueuedConnection | 信号线程一直阻塞,直到槽返回,适用于二者在不同的线程 |
Qt::UniquedConnection | 防止出现重复关联 |
4.信号槽关联形式
1.使用connect函数,例如
connect(dlg,SIGNAL(dlgReturn(int),this,SLOT(showValue(int)));//这里分别使用SIGNAL和SLOT关键字修饰信号与槽
2.QT5新增的connect重载形式,不需要使用这两个关键字,例如
connect(dlg.&MyDialog::dlgReturn,this,&Widget::showValue);//可以省略this参数
3.使用匿名函数lamada表达式,形如
connect(dlg,&MyDialog::dlgReturn,[=](int value){
ui->label->setText(value);
});
4.使用设计师工具提供的“转到槽”
将直接生成槽函数,用户只需实现定义即可
void MyDialog::on_selectBtn_clicked()
{
//槽函数定
}
5.信号与槽实例
创建两个类,分别是“老师”和“学生”,下课之后,老师发送自定义信号,“饿了”,学生响应该信号,并请老师吃饭。
1.创建两个C++类,一个是Teacher,一个是Student。Teacher中,声明信号hungry
signals:
void hungry();
2.Student中,声明并实现槽函数treat();
public slots:
void treat();
void Student::treat(){
qDebug()<<"yxx,我想请你吃牛肉泡馍";
}
3.Qt界面师类widget中,关联信号与槽,并拓展使用了lamada表达式关联信号与信号
widget.cpp中代码如下:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//为两个对象分配空间
yxx0803 = new Teacher(this);
jackchen = new Student(this);
connect(yxx0803,&Teacher::hungry,jackchen,&Student::treat);
classIsOver();
QPushButton *btn = new QPushButton(this);
btn->setText("下课!");
btn->move(100,100);
connect(btn,&QPushButton::clicked,[=](){
yxx0803->hungry();
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::classIsOver()
{
emit yxx0803->hungry();
}
4.效果,程序运行,由于classIsOver被调用,会打印一次请客,当点击按钮也会打印请客吃饭。
6.传送门
END |
🎏文章原创,首发于CSDN论坛。
🎏欢迎点赞❤❤收藏⭐⭐打赏💴💴!
🎏欢迎评论区或私信指出错误❌,提出宝贵意见或疑问❓。