目录
信号槽机制
Qt 中的信号
槽函数
槽函数定义
通过代码创建槽函数
通过ui文件创建槽函数
自定义信号
带参数的信号与槽
信号槽断开绑定
信号槽机制
信号和槽机制是 Qt 中一个非常重要的一个机制, 因为有信号和槽机制, 就可以通过某些条件的触发来调用这些槽函数, 而槽函数实际上也就是回调函数.
Qt 中的信号
-
信号源: 信号源表示的是由哪一个控件发出信号
-
信号的类型: 用户的不同的操作,可能触发不同的信号 点击的话, 就会触发被点击的信号 输入框中移动光标, 会触发移动光标的信号 以及勾选复选框等也会触发信号
-
信号的处理方式: 槽函数(slot) -> 回调函数
-
绑定信号与槽: connect 函数
Qt 中的信号实际上就是 Qt 中类的一些函数, 但是我们也可以自己实现信号的函数, 声明信号函数的时候需要写明 signals, 而再信号的定义中,其实是不需要定义的, 我们只需要声明即可
当我们需要发射信号的时候,我们需要写明 emit 但是现在也可以不写 emit 但是为了可读性, 我们还是建议写清楚
槽函数
槽函数就是一个函数, 这个函数用于处理当某个信号到来之后的任务, 所以槽函数实际上是很早就定义出来的, 再信号被触发之前定义出来的.
槽函数也是可以我们自己定义的, 不过 Qt 中也内置了一些槽函数, 比起信号自定义来说, 槽函数的自定义是更常见的.
槽函数的自定义是很简单的, 只需要再声明参函数前加一个 public slots , 不过现在也可以不写 public slots
槽函数定义
通过代码创建槽函数
下面我们实现一个案例: 我们可以创建一个按钮, 按下按钮后, 就会修改窗口的标题.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 1. 创建一个 QpushButton
QPushButton* button = new QPushButton(this);
button->setText("按钮");
button->move(200, 200);
// 2. 绑定信号与槽函数
connect(button, &QPushButton::clicked, this, &MainWindow::process_clicked);
}
void MainWindow::process_clicked()
{
// 当点击按钮的时候吗,就会调用这个槽函数
// 槽函数中修改窗口标题
this->setWindowTitle("窗口标题被修改");
}
在 MainWindow 中声明的时候, 可以像普通函数一样声明, 也可以在槽函数前面添加 public slots
这个代码的作用就是可以修改窗口的标题, 在按钮被按下的时候
通过ui文件创建槽函数
上面我们通过代码的方式来创建了槽函数,但是我们也可以使用ui文件的方式来创建槽函数,具体怎么样,我们下面看.
首先我们需要在ui界面上拖拽一个按钮:
然后我们右键点击按钮,此时就会弹出一个框, 我们选择里面的转到槽
此时就会弹出一个对话框
这里面就是关于 QPushButton 中的所有的槽函数, 我们选择 clicked 函数,此时 Qt 就会自动帮我们生成一个槽函数,并且不需要我们手动的调用 connect 函数.
void Widget::on_pushButton_clicked()
{
}
这个函数的命名是有规则的, 其中 on 开头,然后是控件名, 后面是相关的槽函数,而 Qt 就是根据这个函数名调用的这个槽函数, 所以当这个函数名被修改后,信号出发后也就不会调用对应的槽函数了.
自定义信号
虽然信号也可以自定义, 但是实际上自定义信号是很少见的, 因为Qt中自带的信号已经可以满足绝大多数的场景了, 而槽函数的自定义才是最常见的
而Qt中的信号,实际上也就是所谓的成员函数, 但是在信号的声明中,就需要在函数声明前写 signals, 而且信号是只需要声明的,不需要我们自己定义.
信号函数的返回值必须是 void 的,但是参数的话,是没有限制的.
下面我们写一个案例,这个案例就是通过按钮来修改窗口标题, 但是按钮的槽函数中并不执行修改窗口标题的任务, 按钮对应的槽函数中进行发射自定义信号, 自定义信号中绑定的槽函数进行修改窗口标题.
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 绑定 my_signal 信号和自定义槽函数
// my_signal 是自定义信号
connect(this, &Widget::my_signal, this, &Widget::handle_my_signal);// handle_my_signal 是自定义槽函数
}
// 按钮对应的槽函数
void Widget::on_pushButton_clicked()
{
// 点击按钮会触发该函数
// 该函数中进行发射 my_signal 信号
emit my_signal();
}
// my_signal 对应的槽函数
void Widget::handle_my_signal()
{
// 在自定义槽函数中进行修改窗口标题
this->setWindowTitle("通过自定义槽函数修改窗口标题");
}
槽函数的声明和信号的声明
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
// 信号声明
void my_signal();
private slots:
// 槽函数声明
void on_pushButton_clicked();
void handle_my_signal();
private:
Ui::Widget *ui;
};
带参数的信号与槽
信号和槽实际上也就是一种函数,既然是函数,那么也就是一定可以有参数,那么信号和槽的参数需要怎么传递呢?
实际上信号和槽函数的参数是有一定关系的,对于信号函数而言,绑定的槽函数的参数是需要与信号的参数是一致的,或者信号的参数多于槽函数的参数。
那么为什么需要带参数呢?带参数可以实现代码复用,因为可能有很多相同的逻辑,知识参数不同而已,所以就没必要写类似的代码了,而是只需要加个参数就可以了。
下面我们实现一个案例,就是两个按钮控制窗口标题,使用同一个信号和槽:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 绑定自定义信号和槽函数
connect(this, &Widget::set_window_title, this, &Widget::handle_set_window_title);
}
void Widget::handle_set_window_title(QString text)
{
// 修i该窗口标题为 text
this->setWindowTitle(text);
}
// 通过 ui 界面生成的槽函数
void Widget::on_pushButton_clicked()
{
// 设置窗口标题为1
// 发射信号
setWindowTitle("设置窗口标题为1");
}
void Widget::on_pushButton_2_clicked()
{
// 设置窗口标题为2
setWindowTitle("设置窗口标题为2");
}
信号槽断开绑定
如果当我们想要将一个信号绑定其他的槽函数我们应该怎么做呢? 我们是可以直接将该信号和其他的槽函数connect吗? 并不是,在 Qt 中一个信号可以绑定多个槽函数,而一个槽函数也可以被多个信号绑定,如果直接使用connect的话,那么就是将一个信号绑定了多个槽函数,所以需要先断开再去绑定其他的槽函数。
下面写一个案例,按钮按下后修改窗口标题,然后打印,按下下面的按钮则会切换一个槽函数绑定,另外一个槽函数也是修改窗口标题并打印
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 1. 先绑定 pushButton1 和 handle_clicked1
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handle_clicked1);
}
void Widget::handle_clicked1()
{
setWindowTitle("修改窗口标题1");
qDebug() << "handle_clicked1";
}
void Widget::handle_clicked2()
{
setWindowTitle("修改窗口标题2");
qDebug() << "handle_clicked2";
}
// 将 pushButton 绑定的 handle_clicked1 切换为 handle_clicked2
void Widget::on_pushButton_2_clicked()
{
// 1. 断开之前的链接
disconnect(ui->pushButton, &QPushButton::clicked, this, &Widget::handle_clicked1);
// 2. 重新链接
connect(ui->pushButton, &QPushButton::clicked, this, &Widget::handle_clicked2);
}