一.信号和槽概念
1. 信号(Signal)
概念 :
信号是 Qt 对象在状态发生变化 或事件发生 时自动发出的通知。
比如按钮被点击、文本框内容变化、定时器超时等,都会发出相应信号。
本质:
它只是一个函数声明 (没有函数体),由 Qt 的
moc
工具生成底层实现。发出信号时,不关心有没有槽接收,也不关心槽的实现细节。
信号可以携带参数,将数据一并传递给槽。
信号本质就是函数,可以分为两类。
1.内置信号,就是系统提供的信号,Qt 各种控件已经在类内部声明并实现的信号eg.&QPushButton::clicked 直接使用就可以。
2.自定义信号 ,只需要在.h文件中进行声明就可以,不需要定义实现。
如何才能触发出自定义的信号呢?
emitvalueChanged(); 当然不写emit也行,不过最好还是写上表示发送自定义信号。
2. 槽(Slot)
概念 :
槽是一个可以被信号调用的普通成员函数,用于处理信号传递过来的事件或数据。
本质:
槽函数和普通成员函数没有区别,只是通过
connect()
机制与信号关联后,会在信号触发时被自动调用。槽函数可以有参数,也可以没有,参数类型和顺序需要与信号保持一致(或是信号的参数可以转换为槽的参数类型)。
槽就相当于一个回调函数,发送了某个信号调用对于应的槽函数进行处理。
槽函数需要在.h文件中声明,并在.cpp文件中实现定义(处理信号的逻辑)
信号和槽的参数关系信号和槽函数都可以有参数。信号和对应连接的槽函数有规则
1.信号函数的参数数量<=槽函数的参数槽函数可以少接收一些参数,但不能多于信号提供的参数。多出来的信号参数会被自动丢弃
2.信号函数的参数能和惨函数参数类型相同或者能隐式类型转换
二.connect()函数
那怎么把信号和槽关联起来呢?
connect() 用于建立信号和槽之间的连接,让某个信号触发时自动调用对应的槽函数。
static QMetaObject::Connection connect( const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection );
sender:信号发出者
signal:信号(函数指针或 SIGNAL 宏)
receiver:槽接收者
slot:槽(函数指针或 SLOT 宏)
type :连接类型(
Qt::AutoConnection
默认)eg.
connect(myButton,&QPushButton::clicked,this,&My_MainWindow::myhandle);
1.myButton 信号从哪一个控件发出的
2.&QPushButton::clicked 哪一个信号函数
3.this(当前窗口对象) 谁接收信号
4.&My_MainWindow::myhandle 对应关联的槽函数
三.信号和槽基本用法
1. 创建一个控件(信号的发起者)
有两种方式:
1.代码创建
这种方式创建的是局部变量(作用域在构造函数里)。
也可以在**.h 头文件里提前声明为成员变量,这样生命周期和类对象一致**
2.图形化界面创建
在 .ui 文件中直接拖拽控件到窗体上,保存后编译会自动生成对应的对象(在 ui_*.h 里)
2. 信号
信号有两种来源:
内置信号 :Qt 控件自带的,比如
QPushButton::clicked()
。自定义信号:
在类的
signals:
区域声明(不需要实现),使用
emit
发射。3.声明并定义槽函数
1.代码生成的,手动.h声明 .cpp定义槽函数
2.如果是通过图形化界面生成的控件 就可以对控件 右键 选择信号名称,
Qt 会自动在
.h
里声明并在.cpp
里定义槽函数。
4. 连接(connect)信号和槽
1.通过代码生成的控件需要手动连接
2.通过图形化界面生成的控件自动连接 不需要显示连接
注意:如果自己再手动连接一次,就会变成重复连接,导致一次信号触发两次槽函数
5. 断开连接(disconnect)
必须用与连接时相同的方式来断开:
如果是函数指针连接,就用函数指针断开:
如果是宏方式连接(UI 自动生成的槽),需要用宏方式断开。
如果要断开所有槽 ,可以把槽参数设为
nullptr
:
disconnect(ui->pushButton, nullptr, this, nullptr);
这两个nullptr分别代表,所有的信号对所有的槽函数都进行断开
使用 Lambda 表达式定义槽函数
在 Qt 中,槽函数不仅可以是类成员函数,还可以直接使用 lambda 表达式 。
Lambda 表达式的本质是一个匿名函数 ,特别适合一次性使用的回调场景,比如临时响应某个信号,不想单独写一个成员函数时。