QT中的信号与槽
- 一、信号与槽函数的作用
- 二、如何关联信号与槽函数
- 1、借助集成开发环境,右键转到槽函数
- 示例代码:
- 2、调用connect函数手动关联信号与槽函数
- 三、扩展
- 四、总结信号与槽的特点
- 1、一个类如果要使用信号以及槽函数,那么该类的定义中必须加上Q_OBJECT宏定义
- 2、同一个槽函数,可以被不同对象的信号关联
- 3、同一个信号,可以关联不同的槽函数
- 4、信号的发送者跟信号之间必须是所属关系(发送者对应的类里面必须有这个信号)
- 5、信号带参数,槽函数可以带参数,也可以不带参数
- 五、获取信号的发送者
- 示例代码:
- 六、自定义信号,发送信号
- 示例代码:
一、信号与槽函数的作用
用来在组件和组件,组件和窗口之间通信
- 信号:QT中给每个组件都定义了信号,每个信号都有它特定的触发条件(QT助手查询到每个信号的触发条件)
QT中所有的信号,本质上都是个函数,信号只有声明,没有源代码
比如:以按钮为例,常用的信号如下[signal] void QAbstractButton::clicked(bool checked = false) //当按钮按下去,然后松开的时候自动触发这个信号[signal] void QAbstractButton::released() //按钮松开会触发该信号[signal] void QAbstractButton::pressed() //按钮按下去触发该信号
- 槽函数:当某个信号触发的时候,跟这个信号对应的槽函数会被自动调用执行
二、如何关联信号与槽函数
关联信号与槽函数:就是使选择的信号跟槽函数形成一一对应关系
1、借助集成开发环境,右键转到槽函数
- 头文件中会自动生成槽函数的声明
private slots: //声明了一个私有的槽函数void on_pushButton_clicked(); //槽函数的原型声明
- 在源码.cpp文件中自动生成的槽函数的定义
on_对象的名字_信号的名字();
示例代码:
// login.cpp
#include "loginwin.h"
#include "ui_loginwin.h"
#include <QLabel>
#include <QFont>
#include <QLineEdit>
#include <QPushButton>
#include <iostream>
#include <QDebug>
using namespace std;
loginwin::loginwin(QWidget *parent): QMainWindow(parent), ui(new Ui::loginwin)
{ui->setupUi(this);//通过写代码把登录界面的ui做出来//第一步:标签//父窗口:这个组件(控件)等一会在哪个窗口上显示,这个窗口就是父窗口QLabel *lb1=new QLabel("学生管理系统",this);//设置按钮的坐标,宽高/*规律:任何组件,属性都有对应的设置方法,方法的名字统一叫做setxxx()比如:属性geometry --》对应的方法setGeometry()*/lb1->setGeometry(200,10,400,100);QFont myfont("楷体",24);lb1->setFont(myfont);//设置样式lb1->setStyleSheet("color:rgb(255,0,0);");//第二步:两个单行输入框QLineEdit *le1=new QLineEdit(this);QLineEdit *le2=new QLineEdit(this);//设置坐标,宽高le1->setGeometry(220,130,300,50);le2->setGeometry(220,220,300,50);//设置默认提示文字le1->setPlaceholderText("请输入用户名");le2->setPlaceholderText("请输入密码");//设置用户名,密码位数le1->setMaxLength(8);le2->setMaxLength(8);//设置密码隐藏le2->setEchoMode(QLineEdit::Password);//设置样式le1->setStyleSheet("border:2px solid#ff0000;");le2->setStyleSheet("border:2px solid#ff0000;");//设置字体le1->setFont(myfont);le2->setFont(myfont);//第三步:两个按钮QPushButton *bt1=new QPushButton("登录",this);QPushButton *bt2=new QPushButton("注册",this);bt1->setFont(myfont);bt2->setFont(myfont);//设置坐标,宽高bt1->setGeometry(200,300,100,50);bt2->setGeometry(450,300,100,50);//给主窗口设置边框图片this->setStyleSheet("QMainWindow{border-image: url(C:/Users/Administrator/Desktop/share/4.jpeg);}");
}loginwin::~loginwin()
{delete ui;
}//跟登录按钮有关的槽函数
//槽函数的定义--》代码由程序员来编写
void loginwin::on_pushButton_clicked()
{//C++的输出//cout<<"登录按钮被点击(按下去,然后松开)"<<endl;//cout<<"loginbt clicked"<<endl;//QT特有的输出,自动换行,不需要回车qDebug()<<"登录按钮被点击(按下去,然后松开)";
}//跟release信号有关的槽函数
void loginwin::on_pushButton_released()
{qDebug()<<"登录按钮松开";
}
//跟pressed信号有关的槽函数
void loginwin::on_pushButton_pressed()
{}// login.h
#ifndef LOGINWIN_H
#define LOGINWIN_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class loginwin; }
QT_END_NAMESPACEclass loginwin : public QMainWindow
{Q_OBJECTpublic:loginwin(QWidget *parent = nullptr);~loginwin();//翻译qt程序--》uic和moc(qt程序除了c++代码之外还有qt特有的(例如信号与槽),所有需要翻译成c++代码)
//slots是QT特有的关键字,C++中没有
private slots: //声明私有的槽函数//在源码.cpp文件中自动生成的槽函数的定义,命名有规律//on_对象的名字_信号的名字();void on_pushButton_clicked(); //槽函数的原型声明void on_pushButton_released(); //槽函数的原型声明void on_pushButton_pressed(); //槽函数的原型声明private:Ui::loginwin *ui;
};
#endif // LOGINWIN_H
2、调用connect函数手动关联信号与槽函数
有些场合无法右键转到槽(比如:按钮不是ui设计师拖过去,而是通过写代码new出来)
- 写法1:
connect(QObject *sender, PointerToMemberFunction signal,QObject *receiver, PointerToMemberFunction method)
- 写法2
connect(发送者指针,&类的名字::信号的名字,接收者,&类的名字::槽函数)参数:sender --》信号的发送者,指针signal --》发送什么信号receiver --》信号的接收者method --》需要调用的槽函数槽函数命名时候,可以跟自动生成的槽函数命名规律保持一致,也可以自行单独命名
比如:connect(ui->handlebt,SIGNAL(clicked(bool)),this,SLOT(fun())); //关联了handlebt这个按钮的clicked信号和槽函数fun()
QT使用技巧:头文件中声明了函数,右键选择refactor,可以在.cpp生成函数的定义
三、扩展
QObject --》QT中所有类的基类
作为形参的好处:实参可以传递任何类型(因为QT中所有的类都是QObject的子类)
四、总结信号与槽的特点
1、一个类如果要使用信号以及槽函数,那么该类的定义中必须加上Q_OBJECT宏定义
Q_OBJECT:QT把它称为元对象系统,作用支持信号与槽这种机制
2、同一个槽函数,可以被不同对象的信号关联
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 同一个槽函数,可以被不同对象的信号关联connect(ui->btn1, SIGNAL(clicked()), this, SLOT(btn()));connect(ui->btn2, SIGNAL(clicked()), this, SLOT(btn()));connect(ui->btn3, SIGNAL(clicked()), this, SLOT(btn()));
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::btn()
{qDebug()<<"按钮按下";
}
//===========================================//
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void btn();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
3、同一个信号,可以关联不同的槽函数
槽函数的调用顺序跟关联的先后顺序一致,先关联的先调用
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//同一个信号,可以关联不同的槽函数//槽函数的调用顺序关联的先后顺序一致,先关联的先调用connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(btn2()));connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(btn1()));connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(btn3()));
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::btn1()
{qDebug()<<"按下btn1";
}void MainWindow::btn2()
{qDebug()<<"按下btn2";
}void MainWindow::btn3()
{qDebug()<<"按下btn3";
}
//=======================================================//
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void btn1();void btn2();void btn3();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
4、信号的发送者跟信号之间必须是所属关系(发送者对应的类里面必须有这个信号)
信号的接收者跟槽函数之间必须是所属关系(接收者对应的类里面必须有这个槽函数)
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//自己手动管理按钮的clicked信号跟自己写的槽函数/*信号的发送者跟信号之间必须是所属关系(发送者对应的类里面必须有这个信号)信号的接收者跟槽函数之间必须是所属关系(接收者对应的类里面必须有这个槽函数)*///错误1:信号发送者跟信号之间不是所属关系//connect(ui->pushButton,SIGNAL(textChanged(QString)),this,SLOT(fun()));//错误2:信号接收者跟槽函数之间不是所属关系//connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(myfun()));connect(ui->pushButton,SIGNAL(clicked()),ui->lineEdit,SLOT(fun()));
}MainWindow::~MainWindow()
{delete ui;
}
//自己手写的槽函数
void MainWindow::fun()
{qDebug()<<"按钮被点击了";
}// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots://自己手写槽函数,命名可以跟右键转到槽一样的命名,也可以随意命名void fun();
private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
5、信号带参数,槽函数可以带参数,也可以不带参数
区别:
- 槽函数带参数,参数必须跟信号保持一致,表示槽函数接收信号传递过来的参数
- 槽函数不带参数,表示不接收信号传递过来的参数
注意:
- 如果信号没有任何参数,此时槽函数也不可以有任何参数
- 信号带了参数,connect写的时候不要写参数的名字,只需要写参数的类型
- 槽函数带了参数,connect写的时候不要写参数的名字,只需要写参数的类型
五、获取信号的发送者
作用:当多个组件对象共用一个槽函数的时候,程序员需要知道是哪个组件对象触发的信号,此时就要获取信号的发送者
QObject *sender() const返回值:返回一个指针,该指针指向信号的发送者
QT中转换函数qobject_cast(QObject *object) //把父类的指针转换成子类地址
示例代码:
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 同一个槽函数,可以被不同对象的信号关联connect(ui->btn1, SIGNAL(clicked()), this, SLOT(btn()));connect(ui->btn2, SIGNAL(clicked()), this, SLOT(btn()));connect(ui->btn3, SIGNAL(clicked()), this, SLOT(btn()));
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::btn()
{
// qDebug()<<"按钮按下";// 获取信号的发送者,并判断哪个按钮被按下QObject *is_sender = sender();if(is_sender == ui->btn1)qDebug()<<"按钮1按下";else if(is_sender == ui->btn2)qDebug()<<"按钮2按下";else if(is_sender == ui->btn3)qDebug()<<"按钮3按下";// QT中转换函数的使用QPushButton *btn = qobject_cast<QPushButton *>(is_sender);btn->setStyleSheet("background-color:rgb(0,255,0);");
}// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void btn();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
六、自定义信号,发送信号
//自定义信号语法格式signals:// 自定义信号;void mysignal(参数); //参数的类型个数依据需要自行添加
//发送信号//注意注意注意:自定义的信号必须程序员主动调用emit发送,不能自动触发的emit mysignal(实参);
示例代码:
// 第一个界面:mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "info_win.h"
#include <QString>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}
// 登录按钮的槽函数
void MainWindow::on_pushButton_clicked()
{// 获取输入的用户名和密码QString account = ui->lineEdit->text();QString pswd = ui->lineEdit_2->text();if(account == "aaa" && pswd == "123"){//创建第二个界面对象,必须传递this指针(把第一个界面的地址传给第二个界面)info_win *info_w = new info_win(this);// 将第一个界面的账号和密码传递给第二个界面 --信号发送connect(this, SIGNAL(sendSign(QString, QString)), info_w, SLOT(recvSlot(QString, QString)));emit sendSign(account, pswd);qDebug()<<"第一界面的地址是"<<this;// 显示第二个界面info_w->show();this->hide();}else{qDebug()<<"账号或密码错误,重新输入";}
}//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();signals: //自定义信号void sendSign(QString, QString);private slots:void on_pushButton_clicked();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H