Qt-信号和槽

一.信号和槽概念

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. 信号

信号有两种来源:

  1. 内置信号 :Qt 控件自带的,比如 QPushButton::clicked()

  2. 自定义信号

    • 在类的 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 表达式的本质是一个匿名函数 ,特别适合一次性使用的回调场景,比如临时响应某个信号,不想单独写一个成员函数时。