文章目录
- [3. 信号和槽的使用](#3. 信号和槽的使用)
-
- [3.2 查看内置信号和槽](#3.2 查看内置信号和槽)
- [3.3 通过 Qt Creator 生成信号槽代码](#3.3 通过 Qt Creator 生成信号槽代码)
- [3.4 第二种创建槽函数的方式](#3.4 第二种创建槽函数的方式)
3. 信号和槽的使用
3.2 查看内置信号和槽
两个问题:
咋知道的
QPushButton有个clicked信号?咋知道的
QWidget有一个close槽?
Qt里到底都提供了哪些内置的信号和槽可以让我们直接使用呢?大家在翻阅文档的时候,如果在当前类中没有找到对应的线索,不妨看看这个类的父类。
系统自带的信号和槽通常是通过 "Qt 帮助文档" 来查询。如上述示例,要查询 "按钮" 的信号,在帮助文档中输入:
QPushButton,
- 首先可以在 "
Contents" 中寻找关键字signals,- 如果没有找到, 继续去父类中查找. 因此我们去他的父类
QAbstractButton中继续查找关键字signals



这里的 clicked() 就是要找的信号。这里的参数checked暂时用不到,后面遇到了再说。
槽函数的寻找方式和信号一样,只不过它的关键字是 slot 。
connect的具体用法:
cpp
bool connect(const QObject *sender,
const char *signal_,
const QObject *receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection);
我们可以看到第2,4个参数类型都是char*。
cpp
connect(button,&QPushButton::clicked,this,&Widget::close);
但是这里的第2,4个参数类型是void(*)(),是函数指针,但是函数指针有很多种。
C++中,不允许你使用两个不同的指针类型,相互赋值,(函数传参,本质上就是赋值)
cpp
void(*)()
bool(*)()
即使是这两个函数指针的类型都是不一致的!!

这个函数声明,是以前l日版本的Qt的connect函数的声明,以前版本中,传参的写法和现在其实也是有区别的。
此时,给信号参数传参,要搭配一个SIGNAL宏。
给槽参数传参,搭配一个SLOT宏。
SIGNAL宏和SLOT宏会将传入的函数指针转成char*
cpp
connect(button,SIGNAL(&QPushButton::clicked),this,SLOT(&Widget::close);
Qt5开始,对上述写法做出了简化。不再需要写SIGNAL和SLOT宏了。
给connect提供了重载版本,重载版本中,第二个参数和第四个参数成了泛型参数,允许咱们传入任意类型的函数指针了。
也就是CPP泛型编程

此时connect函数就带有了一定的参数检查功能。
如果你传入的第一个参数和第二个参数不匹配,或者第三个参数和第四个参数不匹配(不匹配指的是:2,4参数的函数指针,不是1,3参数的成员函数)
此时代码编译出错。
3.3 通过 Qt Creator 生成信号槽代码
Widget.h
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handleClicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
Widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button = new QPushButton(this);
button->setText("按钮");
button->move(100,100);
connect(button,&QPushButton::clicked,this,&Widget::handleClicked);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleClicked()
{
//按下按钮,修改窗口标题
this->setWindowTitle("按钮已经按下");
}
运行:

点击

3.4 第二种创建槽函数的方式
先新建项目,点击.ui控件
将Push Button按钮拖到页面

右键按钮,点击转到槽


这个窗口就列出了QPushButton给我们提供的所有的信号(还包含了QPushButton父类的信号)
对于普通按钮来说, 使用 clicked 信号即可。 clicked(bool) 没有意义的,具有特殊状态的按钮(比如复选按钮)才会用到 clicked(bool) 。
双击clicked,就会自动生成一个函数并跳转,并且声明也有

运行,点击

可以发现这里没有connect,并且在对应的ui_widget文件里面也没有。
在Qt中,除了通过connect来连接信号槽之外,还可以通过函数名字的方式来自动连接。

说明:
自动生成槽函数的名称有一定的规则。槽函数的命名规则为:
on_XXX_SSS,其中:
以 "
on" 开头,中间使用下划线连接起来;"
XXX" 表示的是对象名(控件的objectName属性)。"
SSS" 表示的是对应的信号。如:"
on_pushButton_clicked()" ,pushButton代表的是对象名,clicked是对应的信号。
按照这种命名风格定义的槽函数,就会被Qt自动的和对应的信号进行连接。但是咱们日常写代码的时候,除非是
IDE自动生成,否则最好还是不要依赖命名规则,而是显式使用connect更好。一方面显式
connect可以更清晰直观的描述信号和槽的连接关系,另一方面也防止信号或者槽的名字拼写错误导致连接失效。
当函数名符合上述规则之后,Qt就能自动的把信号和槽给建立上联系。
如果我们把on_pushButton_clicked改成on_pushButton_click,那么运行后点击按钮无反应,没有连接槽,并且出现下面提示,因为后者不存在Qt中。

Qt中调用这个函数的时候,就会触发上述自动连接信号槽的规则
正是在自动生成的ui_widget.h中调用的。

如果我们通过图形化界面创建控件,还是推荐使用这种快速的方式来连接信号槽
如果我们是通过代码的方式来创建控件,还是得手动connect。(代码中没有调用connectSlotsByName)