1.信号和槽扫盲
(1)当信号发出后,先执行槽函数,在执行信号后面的函数(单线程)。
(2)当信号与多个槽函数连接时,按照connect的连接顺序进行执行。
上面的图片中,发出downloadFile()信号后,会依次执行onDownloadFile2() 、onDownloadFile3() 、onDownloadFile1()
(3)信号和槽只是在代码形式上进行了分离,本质上仍按顺序执行调用函数。
2.信号和槽的高级用法
(1)获取信号发出者:sender()
当前窗口有上传和下载两个按钮,当按下他们时候获取信号发出者以及文本:
代码展示:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->btnUpload,SIGNAL(clicked()),this,SLOT(onButtonClicked()));
connect(ui->btnDownload,SIGNAL(clicked()),this,SLOT(onButtonClicked()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::onButtonClicked()
{
//获取信号发出者
QPushButton* button = dynamic_cast<QPushButton*>(sender());
//获取文本
qDebug() <<button->text();
}
(2)断开连接:disconnect()
bool QObject::disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
演示连接的信号和槽:
connect(ui->btnUpload,SIGNAL(clicked()),this,SLOT(onButtonClicked()));
connect(ui->btnDownload,SIGNAL(clicked()),this,SLOT(onButtonClicked()));
断开所有连接:后面三个参数全部设为nullptr
//写法一
disconnect(ui->btnUpload,nullptr,nullptr,nullptr);
//写法二
ui->btnUpload->disconnect(nullptr,nullptr,nullptr);
断开指定信号的所有连接:后面两个参数设为nullptr
disconnect(ui->btnUpload,SIGNAL(clicked()),nullptr,nullptr);
断开接受者的所有连接:
disconnect(ui->btnUpload,nullptr,this,nullptr);
断开接收者的某个槽函数连接:
disconnect(ui->btnUpload,nullptr,this,SLOT(onButtonClicked()));
(3)QSignalMapper
使用QSignalMapper 来匹配信号发送,来减少connect()代码。
当使用自定义控件时,如果不断添加新的小部件(如按钮,标签),会不断的新增connect代码来绑定信号和槽。这样代码会原来越多,并且在主函数中也会新增各种connect代码和自定义的信号和槽函数。为了优化代码,可以使用QSignalMapper来绑定所有的同一种部件(如按钮),这样后面增加新的小部件也不用再增加代码。
#include "toolbarwidget.h"
#include "ui_toolbarwidget.h"
#include <QFileDialog>
#include <QDebug>
#include <QSignalMapper>
ToolBarWidget::ToolBarWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ToolBarWidget)
{
ui->setupUi(this);
//绑定自定义的退出登录信号
connect(ui->BtnQuit,&QPushButton::clicked,this,&ToolBarWidget::quitLogin);
//首先创建一个mapper对象
QSignalMapper* mapper = new QSignalMapper(this);
//遍历所有的按钮
QList<QPushButton*> buttonList = findChildren<QPushButton*>();
//绑定信号和槽
for(auto btn : buttonList)
{
connect(btn,SIGNAL(cilcked()),mapper,SLOT(map()));
//检查按钮和文本,如果是绑定关系,就发出mapped信号
mapper->setMapping(btn,btn->text());
}
//将信号发射出去
connect(mapper,SIGNAL(mapped(QString)),this,SIGNAL(buttonClicked(QString)));
}
在主函数(主窗口)中,就只需绑定一次,只需创建一个统一的槽函数来对所有的小部件(比如按钮)进行信号的响应。
connect(ui->widgetToolBar,&ToolBarWidget::buttonClicked,this,&UiMain::onButtonClicked);
假如是按钮,通过匹配按钮的文本,来进行不一样的操作。
void UiMain::onButtonClicked(const QString &text)
{
if(text == "确定")
{
/* 相应代码 */
}
if(text == "刷新")
{
/* 相应代码 */
}
}