Qt信号和槽
- 标准的信号和槽函数
- Qt中的槽函数
- Qt中的信号
- connect
- 案例
- 自定义信号和槽
- 案例分析
- 信号槽的拓展
- 信号连接信号案例
- 信号槽的两种连接方式
- Qt5中的处理方式
- Qt4中的处理方式
- Qt5处理信号槽重载问题
- 案例
- lambda表达式
- 简单案例
- Qt中的应用
- 补充知识点
标准的信号和槽函数
QWidget标准的信号和槽函数
此外信号和槽函数是可以被继承的
可以看到QPushButton是有标准的槽函数,但是没有看到信号。
实际上QPushButton是继承了它的父类的信号
Qt中的槽函数
Qt中的槽函数可以是类的成员函数、全局函数、静态函数、Lambda表达式(匿名函数)
Qt中的信号
信号需要使用 signals 关键字进行声明, 使用方法类似于public等关键字
connect
connect(信号发生者,信号,信号接受者,接受者的处理动作);
connect只是做了一个信号注册,具体操作步骤是通过qt框架进行实现的
案例
功能实现: 点击窗口上的按钮, 关闭窗口
功能分析:
- 按钮: 信号发出者 -> QPushButton 类型
- 窗口: 信号的接收者和处理者 -> QWidget 类型
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
// ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}MainWindow::~MainWindow()
{delete ui;
}
不可以将第四个参数写为 &this->close,因为 &this->close 表示的是 MainWindow 类的成员函数指针,而 QPushButton::clicked 信号需要一个成员函数指针,而这个指针的类型是 void (MainWindow:😗)()(即没有参数且没有返回值的成员函数指针)。
自定义信号和槽
案例分析
假设要实现一个类GirlFriend发出hungry信号,一个类Me来接受信号进行处理。
- 1、由于这两个是不同的类,所以应该提供一个窗口类对上面的这两个类进行包装
- 2、在GirlFriend类中只需要声明信号,不需要实现,因为这是信号的发出者
- 3、在Me类的槽函数不仅需要声明也需要实现
主窗口头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "girlfriend.h"
#include "me.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();public slots:void hungrySlot();private:Ui::MainWindow *ui;GirlFriend *g_girl;Me *m_me;
};
#endif // MAINWINDOW_H
主窗口函数实现
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
// ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮g_girl=new GirlFriend;m_me=new Me;//这个hungry是自定义的不由Qt框架提供,需要使用者发射信号 >>>>>>> 窗口中实现connect(g_girl,&GirlFriend::hungry,m_me,&Me::eat);//>>>>>>>>>>>>>>提醒Qt框架有信号connect(ui->hungry,&QPushButton::clicked,this,&MainWindow::hungrySlot);connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::hungrySlot()
{//发射信号emit g_girl->hungry();
}
信号槽的拓展
- 一个信号可以连接多个槽函数, 发送一个信号有多个处理动作
需要写多个connect()连接
槽函数的执行顺序是随机的, 和connect函数的调用顺序没有关系- 信号的接收者可以是一个对象, 也可以是多个对象
一个槽函数可以连接多个信号, 多个不同的信号, 处理动作是相同的
需要写多个connect()连接- 信号可以连接信号
connect(const QObject *sender, &QObject::signal, const QObject *receiver, &QObject::siganl-new);
- 信号槽可以断开信号 --> 很少使用
disconnect(const QObject *sender, &QObject::signal, const QObject *receiver, &QObject::method);
信号连接信号案例
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
// ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮g_girl=new GirlFriend;m_me=new Me;//这个hungry是自定义的不由Qt框架提供connect(g_girl,&GirlFriend::hungry,m_me,&Me::eat);connect(g_girl,&GirlFriend::hungry,this,&MainWindow::eatSlot);//信号连接信号connect(ui->hungry,&QPushButton::clicked,g_girl,&GirlFriend::hungry);//信号连接槽函数//connect(ui->hungry,&QPushButton::clicked,this,&MainWindow::hungrySlot);connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::hungrySlot()
{//发射信号emit g_girl->hungry();
}void MainWindow::eatSlot()
{qDebug()<<"喝尿";
}
信号槽的两种连接方式
Qt5中的处理方式
第二个和第四个参数是函数地址
Qt4中的处理方式
信号槽函数通过宏SIGNAL和SLOT转换为字符串类型
Qt5处理信号槽重载问题
signals:void hungry();void hungry(QString msg);
public slots://槽函数void eat();void eat(QString msg);
解决方案1:使用Qt4的信号与槽的机制(慎用,编译器不会报错如果你写错了)
//Qt4的信号与槽connect(g_girl,SIGNAL(hungry()),m_me,SLOT(eat()));connect(g_girl,SIGNAL(hungry(QString)),m_me,SLOT(eat(QString)));
解决方案2:使用函数指针进行指定
void(GirlFriend::*girl1)()=&GirlFriend::hungry;void(GirlFriend::*girl2)(QString)=&GirlFriend::hungry;void(Me::*point)(QString)=&Me::eat;void(Me::*pointt)()=&Me::eat;connect(g_girl,girl1,m_me,pointt);connect(g_girl,girl2,m_me,point);// >>>>> Qt5connect(g_girl,girl2,this,&MainWindow::eatSlot);// >>>>>> 信号是带参的而槽函数是不带参的 >>>> 直接就是执行eatSlot
案例
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
// ui->closeBtn;//>>>>>>>>>>>>>>>>>>通过ui对象可以操纵所创建的按钮g_girl=new GirlFriend;m_me=new Me;//这个hungry是自定义的不由Qt框架提供
// >>>>>>>>>>>>>> Qt5处理重载void(GirlFriend::*girl1)()=&GirlFriend::hungry;void(GirlFriend::*girl2)(QString)=&GirlFriend::hungry;void(Me::*point)(QString)=&Me::eat;void(Me::*pointt)()=&Me::eat;connect(g_girl,girl1,m_me,pointt);connect(g_girl,girl2,m_me,point);// >>>>> Qt5connect(g_girl,girl2,this,&MainWindow::eatSlot);
//err//connect(g_girl,&GirlFriend::hungry,m_me,&Me::eat);// >>>>> Qt5//connect(g_girl,&GirlFriend::hungry,this,&MainWindow::eatSlot);//Qt4的信号与槽connect(g_girl,SIGNAL(hungry()),m_me,SLOT(eat()));connect(g_girl,SIGNAL(hungry(QString)),m_me,SLOT(eat(QString)));//信号连接信号//connect(ui->hungry,&QPushButton::clicked,g_girl,&GirlFriend::hungry);//信号连接槽函数connect(ui->hungry,&QPushButton::clicked,this,&MainWindow::hungrySlot);connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::hungrySlot()
{//发射信号g_girl->hungry();g_girl->hungry("粑粑");
}void MainWindow::eatSlot()
{qDebug()<<"喝尿";
}
lambda表达式
lambda表达式–>匿名函数
[capture](params) opt -> ret {body;};- capture: 捕获列表- params: 参数列表- opt: 函数选项- ret: 返回值类型- body: 函数体
捕获列表: 捕获一定范围内的变量[] - 不捕捉任何变量[&] - 捕获外部作用域中所有变量, 并作为引用在函数体内使用 (按引用捕获)[=] - 捕获外部作用域中所有变量, 并作为副本在函数体内使用 (按值捕获)拷贝的副本在匿名函数体内部是只读的[=, &foo] - 按值捕获外部作用域中所有变量, 并按照引用捕获外部变量 foo[bar] - 按值捕获 bar 变量, 同时不捕获其他变量[&bar] - 按引用捕获 bar 变量, 同时不捕获其他变量[this] - 捕获当前类中的this指针让lambda表达式拥有和当前类成员函数同样的访问权限如果已经使用了 & 或者 =, 默认添加此选项
简单案例
// 匿名函数的定义, 程序执行这个匿名函数是不会被调用的
[](){qDebug() << "hello, 我是一个lambda表达式...";
};// 匿名函数的定义+调用:
int ret = [](int a) -> int
{return a+1;
}(100); // 100是传递给匿名函数的参数
Qt中的应用
补充知识点
#include<iostream>
using namespace std;class a
{
public:void print(){cout << "1" << endl;}
};int main()
{a a; // 创建对象a.print();// 声明成员函数指针并调用void (a:: * print_ptr)() = &a::print; // 成员函数指针(a.*print_ptr)(); // 通过指针调用
}