文章目录
- 1. QT信号与槽函数
- 2. QT自定义信号和槽函数
1. QT信号与槽函数
QT信号关键要素:
- 信号源:那个控件发送的信号
- 信号类型:用户进行不同的操作,就可能触发不同的信号。
eg:点击按钮,移动鼠标等 - 信号处理方式:使用槽函数(slot)将信号与对应的信号处理函数关联起来(回调函数)
在QT中使用connect函数关联信号和信号处理函数(槽函数),这个函数是QObject类(基类)的静态成员函数
connect函数原型
static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType type= Qt::AutoConnection);
- sender:当前信号是那个控件发送的(信号源)
- singal:信号的类型,发送的是那种信号
- receiver+member:信号如何处理
- receiver:那个对象负责处理(控件)
- member:这个对象怎么处理(函数)
- type:有默认值,一般不填写
QT信号也是QT对象,内部提供一些成员函数,使用时需要注意发送信号和相应的控件符合。
各种控件的信号可以看QT文档
上述的函数声明,是旧版本的QT,旧版本的QT给信号参数传参需要搭配一个SIGNAL宏
给槽函数传参需要搭配一个SLOT宏connect(button,SIGNAL(&QPushButton::clicked),this,SLOT(&QWidget::close));
eg:
#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(200,200);
//点击关闭信号,this指的Widget,通过Widget来响应这个信号,&QWidget::close是QT内置的槽函数,负责控件关闭
connect(button,&QPushButton::clicked,this,&QWidget::close);
}
Widget::~Widget()
{
delete ui;
}
2. QT自定义信号和槽函数
自定义槽函数:
方式一:手动定义函数
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton*button=new QPushButton(this);
button->setText("按钮");
button->move(200,200);
connect(button,&QPushButton::clicked,this,&Widget::handerClick);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handerClick()
{
//按下按钮,设置窗口标题
this->setWindowTitle("按钮按下");
qDebug()<<this->windowTitle();
}
方法二:通过ui界面生成槽函数
这个窗口就是QPushButton控件提供的所有信号
此时这个函数自动会绑定这个按钮的信号(通过函数名称来绑定,函数名为on+按钮的objectname+信号名称)egon_myButton_clicked
,当函数名符合上述规则,QT会对响应控件的信号自动进行绑定(connectSlotsByName函数)
自定义信号:实际开发中比较少,QT内置信号基本已经覆盖控件所有操作,自定义信号一般需要程序员手动发送(emit关键字)
QT信号本质上也是函数(特殊函数,只有函数声明,并且将其声明成QT信号即可,QT编译自动生成这个信号函数)
信号函数的返回值为void,有无参数都可以。
eg:
//.h
#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();
private slots:
void on_myButton_clicked();
private:
Ui::Widget *ui;
//自定义信号,QT扩展的关键字,在qmake扫描带这个关键字后会生成具体代码
signals:
void mySignals();
public:
void handMySignals();
};
#endif // WIDGET_H
//.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//关联自定义信号
connect(this,&Widget::mySignals,this,&Widget::handMySignals);
//初始化时发送自定义信号
emit mySignals();
}
Widget::~Widget()
{
delete ui;
}
void Widget::handMySignals()
{
this->setWindowTitle("自定义信号");
}
带参数的信号和槽函数
当信号带有参数时,槽的参数必须和信号一致,此时发射信号时就可以给这个信号函数传递参数,与之对应的参数就会被传递给槽函数
//.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT //Q_OBJECT宏:在QT中让某个类能够使用信号槽机制,必须要在类最开始的地方声明这个宏。
public:
Widget(QWidget *parent = nullptr);
~Widget();
//自定义信号,QT扩展的关键字,在qmake扫描带这个关键字后会生成具体代码
signals:
void mySignals(const QString&);
public:
void handMySignals(const QString&);
};
#endif // WIDGET_H
//.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//关联自定义信号
connect(this,&Widget::mySignals,this,&Widget::handMySignals);
//初始化时发送自定义信号
emit mySignals("带参自定义信号");
}
Widget::~Widget()
{
delete ui;
}
void Widget::handMySignals(const QString&text)
{
this->setWindowTitle(text);
}
注意:当信号函数参数个数超过了槽函数参数个数,代码可以正常运行,信号多余的参数槽函数接受不到。反之报错
这里这样设计的原因是:信号与槽函数绑定不是一对一的,一个槽函数可能绑定多个信号,如果严格要求信号函数和槽函数参数一致,那么同一个槽函数有些信号无法绑定。使用这样的规则,信号和槽的绑定更加灵活,这样更多的信号就可以绑定到这个槽函数了。
Q_OBJECT宏:在QT中让某个类能够使用信号槽机制,必须要在类最开始的地方声明这个宏。
QT信号和槽机制的优点:
- 解耦合:触发用户的控件和处理用户的操作逻辑解耦合
- 一个信号可以绑定多个槽函数,一个槽函数也可以绑定多个信号(多对多,关联表)
此外可以使用disconnect函数断开信号和槽函数的连接
eg:
void Widget::on_pushButton_clicked()
{
this->setWindowTitle("修改窗口标题");
}
void Widget::on_pushButton_2_clicked()
{
//断开原来按钮的槽函数
disconnect(ui->pushButton,&QPushButton::clicked,this,&Widget::on_pushButton_clicked);
qDebug()<<"重新绑定槽函数";
//重新绑定信号槽
connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handclick);
}
void Widget::handclick()
{
this->setWindowTitle("重新修改窗口标题");
}
此外,在定义槽函数时也可以使用lambda表达式,其本质就是匿名函数,常常用于回调函数
eg:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton*button=new QPushButton(this);
button->setText("按钮");
int* times=new int(1); //这里必须new 因为这是在构造函数中connect的,设计变量声明周期问题,new出的变量必须手动释放,变相提高了声明周期,使得connect函数捕获times指针解引用不会报错
//lambda作为回调函数
connect(button,&QPushButton::clicked,this,[=](){
qDebug()<<"lambda回调函数";
//点击按钮移动按钮
button->move(10*(*times),10*(*times));
*times+=1;
});
emit signals1();
emit signals2();
}