信号和槽 信号和槽是什么
liebian365 2024-11-12 13:09 19 浏览 0 评论
一、Qt信号和槽机制&emit的使用
(一)相关概念
1.信号(Signal)就是在特定情况下被发射的事件
例如PushButton 最常见的信号就是鼠标单击时发射的 clicked() 信号,一个 ComboBox 最常见的信号是选择的列表项变化时发射的 CurrentIndexChanged() 信号。GUI 程序设计的主要内容就是对界面上各组件的信号的响应,只需要知道什么情况下发射哪些信号,合理地去响应和处理这些信号就可以了。
2.槽(Slot)就是对信号响应的函数。槽就是一个函数
与一般的C++函数是一样的,可以定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。
3.信号与槽之间的关联:是用 QObject::connect() 函数实现的,其基本格式是:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
//信号发出者,处理的信号, 信号接收者,处理动作方法(槽函数)。
注解:
- sender 是发射信号的对象的名称
- signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。
- receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。
- SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。
Qt资料领取→「链接」
(二)注意点
1.一个信号可以连接多个槽, 当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行,例如:
- connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
- connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));
2.多个信号可以连接同一个槽,
- connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
- connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
- connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()))
3. 一个信号可以连接另外一个信号
4.严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。
5.使用signals/slots必须要加入宏Q_OBJECT
6. 当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。
7.一定要有signals关键字,定义信号时这个关键字不可或缺,比如我们定义一个信号void signal(),一定要在前面加上关键字“signals:”,
- signals:
- void signal();
- 就像类中的public、protected、pravate一样,但是一定不能在signals前面加上public、protected、private,publi signals:这样写是错误的
8.slots可以写可以不写,一般的函数也可以与signals下的信号关联,我们定义槽函数时可以像signals那样加上slots关键字,也可以不加,但是需要注意的是,如果加上了,那就必须加上public、protected、paivate
- public slots:
- void func();这样写slots:void func();这样写就是错的
- 当然不加上slots的一般函数也可以与信号关联
9.signals下的函数必须是void类型,而且只需要给出声明即可,具体实现QT内部自己处理,但是槽函数一定要实现,从我们角度思考是这种信号处理是一致的,但是槽函数的功能确实根据我们需要自己设计,所以有了这种差异。
10.信号与槽的参数不能是宏和函数指针
11.信号一般与emit配合使用,使用emit发射信号给关联的槽
12.connect若触发,它后面的不会再运行
(三)自定义槽
可当作槽函数的:任意的成员函数,普通全局函数,静态函数。
槽函数需要和信号一致(参数列表,返回值)如果信号没有返回值,槽函数一定没有返回值。
【举例】:让按钮2点击一下,就能改变按钮上的文本。
1.首先,在.h文件中声明:
2.在.cpp文件对该函数进行定义:
3.给按钮联结自定义的槽函数 mySlot:
connect(b2, &QPushButton::released, this, &MainWidget::mySlot);
4.运行
(四)自定义信号
1.信号必须有signals关键字来声明
2.信号没有返回值,但可以有参数。
3.信号就是函数的声明,只需声明,无需定义。
(五)emit发射信号
emit是Qt关键字,像其他关Qt扩展一样,它也会被C++预处理器转换成标准的C++代码。
使用:在A中对B使用信号
主要步骤:信号的创建,槽函数的创建,A类信号和B类槽函数的联接和使用
二、Connect几种方式
(一)说明
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
//信号发出者,处理的信号, 信号接收者,处理动作方法(槽函数)。
- sender 是发射信号的对象的名称
- signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。
- receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。
- SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。
1.
这应该是QT4.0最为传统的方法
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(pushButon1_clicked()));
2.
这应该是QT5.0之后退出来的绑定方法,去掉了之前的宏
connect(ui->pushButton_2,&QPushButton::clicked,this,&::MainWindow::pushButon2_clicked);
3.
C++11出来之后,新的特性就出来,static_cast 用法
connect(ui->pushButton_3, QOverload<bool>::of(&QPushButton::clicked),this,&::MainWindow::pushButon3_clicked);
4.
lamda表达式
connect(ui->pushButton_4, QOverload<bool>::of(&QPushButton::clicked),[=](bool check){
ui->textBrowser->setText("按钮4信号绑定成功");
});
如果槽函数很简单,可以直接利用 lambda表达式进行连接,以减少代码量
这里需要注意 Lambda表达式是C++ 11 的内容,所以,需要再Pro项目文件中加入 CONFIG += C++ 11
(二)例子
1.彻底退出
connect(quitAction,&QAction::triggered,[=](){this->close(); });
2.跳转其他页面
connect(m_button[0], &ClickLabel::clicked, this, [=]() {
zoom(m_button[0]);
m_guideScene->show();
this->hide();
});
3.connect嵌套
//监听每个按钮的点击事件
connect(menuBtn,&MyPushButton::clicked,[=](){
...
//进入到游戏场景
this->hide(); //将选关场景隐藏掉
play = new PlayScene(i+1); //创建游戏场景
//这里注意,每次点击按钮都会新建一个游戏场景对象指针,因此返回时应当删除
...
play->show(); //显示游戏场景
connect(play,&PlayScene::chooseSceneBack,[=](){
this->setGeometry(play->geometry());//设定新窗口的坐标在屏幕上与原先窗口坐标相同
this->show();
delete play;
play = NULL;
});
});
//点击返回//从子页面返回
connect(backBtn,&MyPushButton::clicked,[=](){
QTimer::singleShot(500,[=](){
emit this->chooseSceneBack();
});
});
三、connect 第五个参数
(一)函数原型
connect 函数原型如下,第五个(5种)参数根据接收者和发送者是否在同一个线程不同
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
(二)Qt::ConnectionType 详解
1.Qt::AutoConnection
自动。一般不写就默认是这个,使用这个值会根据实际情况去判断,如果sender和receiver在同一个线程,则自动使用Qt::DirectConnection,如果不在一个线程,则自动使用Qt::QueuedConnection。
2.Qt::DirectConnection
直连。槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。
3.Qt::QueuedConnection
队列连接。槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
4.Qt::BlockingQueuedConnection
阻塞队列连接。槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
5.Qt::UniqueConnection
唯一连接。这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。
四、disconnect函数
disconect函数的原型如下:
bool QObject::disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
(一)使用方法
一般有四种用法:
1.解除myObject对象的所有信号连接,调用后myObject对象发出的所有信号都得不到响应。
disconnect(myObject, 0, 0, 0);
//等同于
myObject->disconnect();
2.解除myObject对象的mySignal信号的所有连接,调用后myObject对象发出的mySignal信号得不到响应。
disconnect(myObject, SIGNAL(mySignal()), 0, 0);
//等同于
myObject->disconnect(SIGNAL(mySignal()));
3.解除myObject对象与myReceiver对象的信号连接,调用后myObject对象发出的所有信号得不到myReceiver对象的响应。
disconnect(myObject, 0, myReceiver, 0);
//等同于
myObject->disconnect(myReceiver);
4.解除myObject对象的mySignal信号与myReceiver对象的mySlot槽的连接,调用后myObject对象发出的mySignal信号得不到myReceiver对象的mySlot槽的响应。
disconnect(myObject, SIGNAL(mySignal()), myReceiver, SLOT(mySlot()));
//等同于
myObject->disconnect(SIGNAL(mySignal(), myReceiver, SLOT(mySlot())));
上述4种用法中,0是通配符,它表示任一信号、任一接收对象、任一槽。
五、blockSignals
blockSignals的函数原型如下:
bool QObject::blockSignals(bool block)
(一)用法
//object发出的信号被阻塞,系统不会调用任何连接到object的处理。
object->blockSignals(true);
//解除信号阻塞
object->blockSignals(false);
六、案例
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget(){}
};
#endif // WIDGET_H
//widget.cpp
#include "widget.h"
#include <QPushButton>
#include <QGridLayout>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
/* 创建控件 */
QPushButton *btnClick = new QPushButton("click me", this);
QPushButton *btnBlock = new QPushButton("block", this);
QPushButton *btnUnblock = new QPushButton("unblock", this);
QPushButton *btnDisconnect = new QPushButton("disconnect", this);
QGridLayout *pLayout = new QGridLayout();
pLayout->addWidget(btnClick, 0, 0);
pLayout->addWidget(btnBlock, 0, 1);
pLayout->addWidget(btnUnblock, 0, 2);
pLayout->addWidget(btnDisconnect, 0, 3);
this->setLayout(pLayout);
/* 信号槽 */
connect(btnClick, &QPushButton::clicked, this, [=]()
{
qDebug() << "点击按钮";
});
connect(btnBlock, &QPushButton::clicked, this, [=]()
{
btnClick->blockSignals(true);
btnBlock->setEnabled(false);
btnUnblock->setEnabled(true);
});
connect(btnUnblock, &QPushButton::clicked, this, [=]()
{
btnClick->blockSignals(false);
btnBlock->setEnabled(true);
btnUnblock->setEnabled(false);
});
connect(btnDisconnect, &QPushButton::clicked, this, [=]()
{
disconnect(btnClick, &QPushButton::clicked, this, 0);
});
}
//main.c
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
结果:
1.按下"click me"按钮,窗口接收到"click me"按钮发出的clicked信号,打印"点击按钮"。
2.然后再按下"block",再次按下"click me"按钮,没有打印"点击按钮"。这是因为 "click me"按钮发出的信号被阻塞了,没有得到响应。
3.然后再按下"unblock"按钮,再次按下"click me"按钮,打印"点击按钮"。这是因为解除了"click me"按钮的信号阻塞。
4.最后按下"disconnect"按钮,此时按下"click me"按钮没有反应。这是因为解除了本窗口与"click me"按钮的clicked信号的连接。
文章转自博客园(ImreW):https://www.cnblogs.com/imreW/p/17099568.html
Qt资料领取→Qt资料领取(视频教程+文档+代码+项目实战)
相关推荐
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
-
明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
-
首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
-
齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...
- Qt界面——搭配QCustomPlot(qt platform)
-
这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
-
老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
-
用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
-
前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...
- 掌握Visual Studio项目配置【基础篇】
-
1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
-
随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...
- Visual Studio Community 2022(VS2022)安装图文方法
-
直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...
- Qt添加MSVC构建套件的方法(qt添加c++11)
-
前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...
- Qt为什么站稳c++GUI的top1(qt c)
-
为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...
- qt开发IDE应该选择VS还是qt creator
-
如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...
- Qt 5.14.2超详细安装教程,不会来打我
-
Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...
- Cygwin配置与使用(四)——VI字体和颜色的配置
-
简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
- Qt界面——搭配QCustomPlot(qt platform)
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
- 掌握Visual Studio项目配置【基础篇】
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
- Visual Studio Community 2022(VS2022)安装图文方法
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)