文章目录
- [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
)