Qt元对象系统 day4

Qt元对象系统 day4

元对象

  • 元对象系统是一个基于标准C++的扩展,为Qt提供了信号与槽机制、实时类型信息、动态属性系统。
  • 元对象可以操作、创建、描述或是执行其他对象,元对象又称为基对象
  • 元对象组成
    • QObject: QT 对象模型的核心,绝大部分的 Qt类都是从这个类继承而来
    • Q_OBJECT:Q_OBJECT宏必须出现在类定义的私有部分,用来开启信号和槽、动态属性系统,或Qt元对象系统提供的其他服务。使用信号与槽时就得包含这个宏
    • MOC:MOC编译器为QObject子类提供了一些实现元对象特性所需要的一些代码。就比如说信号,大家知识在类声明的时候声明了所需要的信号,在MOC编译时,会为信号添加函数定义。
#include <QApplication>
#include <QWidget>class Widget :public QWidget
{Q_OBJECT
public:Widget(QWidget* parent =nullptr):QWidget(parent){}
};int main(int argc, char* argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}//如果把类和main这个文件写在了同一个文件,那么必须在代码最后加上#include[空格]"文件名.moc" 
//这行预处理指令,告诉moc这个文件需要进行元编译,以实现Q_OBJECT宏中声明的函数
#include "main.moc"

使用按钮控件

  • 包含头文件#include <QPushButton>
#include <QApplication>
#include <QWidget>
#include <QPushButton>
class Widget :public QWidget
{//只要用到信号与槽就必须加这个宏Q_OBJECT
public:Widget(QWidget* parent =nullptr):QWidget(parent){//设置窗口大小resize(600, 600);//添加按钮,放到在自己主屏幕上QPushButton *btn = new QPushButton(this);//添加文本btn->setText("小瓜");//移动按钮位置btn->move({300,300});//当点击按钮的时候进行自定义操作connect(btn, &QPushButton::clicked, this, &Widget::on_btn_clicked);}//槽函数void on_btn_clicked(){qDebug() << "你点击了小瓜";}
};int main(int argc, char* argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}//如果把类和main这个文件写在了同一个文件,那么必须在代码最后加上#include[空格]"文件名.moc" 
//这行预处理指令,告诉moc这个文件需要进行元编译,以实现Q_OBJECT宏中声明的函数
#include "main.moc"
  • 运行结果
    在这里插入图片描述

信号与槽

  • 信号与槽:实际就是一个观察者模式(发布-订阅模式),例如按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。这样就让互不干扰的对象建立了联系

  • 槽实际上就是普通的函数,成员函数、全局函数、静态函数、lambda函数都可以!

  • 当我们把对象的信号和槽绑定在一起之后,当信号触发时,与之绑定的槽函数将会自动调用,并把信号的参数传递给槽函数

绑定信号与槽

  • 信号与槽绑定使用QObject::connent()函数实现,其基本格式如下:
 [static] QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method,, Qt::ConnectionType type = Qt::AutoConnection)[static] QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
  • sender:信号发送者,需要传递一个QObject的对象
  • signal:发出的具体信号,需要传递一个函数指针
  • receiver:信号接收者,需要传递一个QObject族的对象
  • method:接收到信号之后,信号接收者处理动作,需要传递一个函数指针(槽函数)
  • type:第一个connect函数独有的参数,表示信号和槽的连接类型;有默认值,一般不需要修改

标准信号与槽

  • 在Qt提供的很多类中都可以对用户触发的某些特定事件进行检测, 当事件被触发后就会产生对应的信号, 这些信号都是Qt类内部自带的, 因此称之为标准信号。
  • 系统自带的信号和槽通常如何查找呢,这个就需要利用帮助文档了,在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入QPushButton,首先我们可以在Contents中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该看当前类从父类继承下来了哪些信号,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个
  • QPushButton的信号
    在这里插入图片描述
  • QWidget的槽
    在这里插入图片描述
  • 断开连接和连接是一样的语法
QObject::disconnect(m_btn, &QPushButton::released, this, &Widget::on_btn_released);
  • 使用连接标识断开连接
QMetaObject::Connection  con = QObject::connect(m_btn,&QPushButton::clicked,this,&Widget::on_btn_released);QObject::disconnect(con);
#include <QApplication>
#include <QWidget>
#include <QPushButton>
class Widget :public QWidget
{//只要用到信号与槽就必须加这个宏Q_OBJECT
public://初始化按钮成员Widget(QWidget* parent =nullptr):QWidget(parent),m_btn(new QPushButton("小瓜", this)){//设置窗口大小resize(300, 300);//连接m_btn信号m_con = connect(m_btn, &QPushButton::clicked, this, &Widget::on_btn_clicked);connect(m_btn, &QPushButton::pressed, this, &Widget::on_btn_pressed);connect(m_btn, &QPushButton::released, this, &Widget::on_btn_released);}//槽函数void on_btn_clicked(){qDebug() << "click";}void on_btn_pressed(){//如果按钮按下,断开released信号连接disconnect(m_btn, &QPushButton::released, this, &Widget::on_btn_released);//使用连接标识断开连接disconnect(m_con);qDebug() << "press";}void on_btn_released(){ qDebug() << "releas";}
protected:QPushButton* m_btn{};//使用连接标识断开连接QMetaObject::Connection m_con{};
};int main(int argc, char* argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}//如果把类和main这个文件写在了同一个文件,那么必须在代码最后加上#include[空格]"文件名.moc" 
//这行预处理指令,告诉moc这个文件需要进行元编译,以实现Q_OBJECT宏中声明的函数
#include "main.moc"
  • 运行结果
    在这里插入图片描述

04 各种槽(成员函数、静态函数、全局函数、labmda)

  • 槽函数的返回值必须是void,槽函数的参数个数不能多于信号的参数个数,信号也可以作为槽函数
#include <QApplication>
#include <QWidget>
#include <QPushButton>
void on_btn_clicked_global()
{qDebug() << __FUNCTION__;
}
class Widget :public QWidget
{//只要用到信号与槽就必须加这个宏Q_OBJECT
public://初始化按钮成员Widget(QWidget* parent =nullptr):QWidget(parent),m_btn(new QPushButton("小瓜", this)){//设置窗口大小resize(300, 300);//连接m_btn信号m_con = connect(m_btn, &QPushButton::clicked, this, &Widget::on_btn_clicked);connect(m_btn, &QPushButton::pressed, this, &Widget::on_btn_pressed);connect(m_btn, &QPushButton::released, this, &Widget::on_btn_released);//把静态函数作为槽函数connect(m_btn, &QPushButton::released, this, &Widget::on_btn_clicked_static);//全局函数作为槽函数connect(m_btn, &QPushButton::released, on_btn_clicked_global);//lambda表达式作为槽函数connect(m_btn, &QPushButton::clicked, []() {qDebug() << "lambda"; });//lambda捕获组件中的文本connect(m_btn, &QPushButton::clicked, [this]() {qDebug() << m_btn->text(); });//获取信号传递的参数connect(m_btn, &QPushButton::clicked, [this](bool checked) {qDebug() << m_btn->text() << checked; });m_btn->setCheckable(true);//设置按钮可以选中}//一般槽函数都加上slots这个标识宏
public slots:void on_btn_clicked(){qDebug() << "click";}void on_btn_pressed(){//如果按钮按下,断开released信号连接disconnect(m_btn, &QPushButton::released, this, &Widget::on_btn_released);//使用连接标识断开连接disconnect(m_con);qDebug() << "press";}void on_btn_released(){ qDebug() << "releas";}static void on_btn_clicked_static(){qDebug() << __FUNCTION__;}
protected:QPushButton* m_btn{};//使用连接标识断开连接QMetaObject::Connection m_con{};
};int main(int argc, char* argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}//如果把类和main这个文件写在了同一个文件,那么必须在代码最后加上#include[空格]"文件名.moc" 
//这行预处理指令,告诉moc这个文件需要进行元编译,以实现Q_OBJECT宏中声明的函数
#include "main.moc"
  • 运行结果
    在这里插入图片描述

自定义信号和重载解决方案

  • 信号是类的成员函数,并且返回类型必须是 void 类型
  • 信号函数只需要声明, 不需要定义(没有函数体实现)
  • 参数可以随意指定, 信号也支持重载
  • 信号需要使用 signals 关键字进行声明, 使用方法类似于public等关键字
  • 在程序中发送自定义信号: 发送信号的本质就是调用信号函数
emit mysignals(); //发送信号
  • emit是一个空宏,没有特殊含义,仅用来表示这个语句是发射一个信号,不写当然可以,但是不推荐。
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>class Login :public QWidget
{Q_OBJECT
public://初始化登录界面的组件Login(QWidget* parent = nullptr) :QWidget(parent), userNameEdit(new QLineEdit(this)), passwordEdit(new QLineEdit(this)), login(new QPushButton("登录", this)){//设置窗口大小resize(600, 400);//设置控件位置居中位,窗口宽度-控件的宽度/2,高度就自行设置userNameEdit->move((width() - userNameEdit->width()) / 2, 50);passwordEdit->move((width() - passwordEdit->width()) / 2, 100);login->move((width() - login->width()) / 2, 150);//连接信号与槽connect(login, &QPushButton::clicked, [=](){auto userName = userNameEdit->text();auto password = passwordEdit->text();//是否验证成功if (1){emit sig_loginSucceed();//emit无任何作用,仅作为标识emit sig_loginSucceed(userName, password);}});//信号转发connect(this, QOverload<>::of(&Login::sig_loginSucceed),this, &Login::login_OK);}
//signals 下面只能放信号
signals:void sig_loginSucceed();void sig_loginSucceed(const QString& userName,const QString& password);void login_OK();
protected:QLineEdit* userNameEdit{};QLineEdit* passwordEdit{};QPushButton* login{};
};int main(int argc, char* argv[])
{QApplication a(argc, argv);Login w;w.show();//信号重载的二义性问题//1.使用函数指针解决void (Login:: * sig_loginSucceed_ptr)(const QString & userName, const QString & password) = &Login::sig_loginSucceed;QObject::connect(&w, sig_loginSucceed_ptr, [](const QString& userName, const QString& password){qDebug() << "登录成功" << "用户名:" << userName << "密码:" << password;});//2.使用QOverload类解决QObject::connect(&w, QOverload<const QString&,const QString&>::of(&Login::sig_loginSucceed), [](const QString& userName, const QString& password){qDebug() << "登录成功2" << "用户名:" << userName << "密码:" << password;});//信号转发QObject::connect(&w, &Login::login_OK, [](){qDebug() << "login_Ok";});return a.exec();
}//如果把类和main这个文件写在了同一个文件,那么必须在代码最后加上#include[空格]"文件名.moc" 
//这行预处理指令,告诉moc这个文件需要进行元编译,以实现Q_OBJECT宏中声明的函数
#include "main.moc"
  • 运行结果
    在这里插入图片描述

窗口切换

  • 新建几个头文件与cpp,在CMAkeLists中添加这几个资源

Widget.h

#ifndef WIDGET_H_
#define WIDGET_H_
#include <QWidget>
#include <QPushButton>
#include "SubWidget.h"
class Widget :public QWidget
{Q_OBJECT
public:Widget(QWidget* parent = nullptr);
protected://初始化为空指针SubWidget*   m_subWidget{};QPushButton* m_curBtn{};
};
#endif // !WIDGET_H_

Widget.cpp

#include "Widget.h"
Widget::Widget(QWidget* parent) :QWidget(parent),m_subWidget(new SubWidget),m_curBtn(new QPushButton("切换到子窗口",this))
{//设置标题setWindowTitle("主窗口");resize(600, 400);connect(m_curBtn, &QPushButton::clicked, [=](){//隐藏主窗口组件this->hide();//切换到子窗口m_subWidget->show();});//接收信号,切换回主窗口connect(m_subWidget, &SubWidget::showMainWidget, [=](){this->show();m_subWidget->hide();});
}

SubWidget.h

#ifndef SUBWIDGET_H_
#define SUBWIDGET_H_
#include <QWidget>
#include <QPushButton>class SubWidget :public QWidget
{Q_OBJECT
public:SubWidget(QWidget* parent = nullptr);
signals://切换窗口信号void showMainWidget();
protected:QPushButton* m_btn{};
};
#endif // !WIDGET_H_

SubWidget.cpp

#include "SubWidget.h"SubWidget::SubWidget(QWidget* parent):QWidget(parent),m_btn(new QPushButton("切换到主窗口",this))
{//设置标题setWindowTitle("子窗口");resize(600, 400);connect(m_btn, &QPushButton::clicked, [=]() {this->hide();//发送切换窗口信号emit showMainWidget();});//或者一句话搞定,和上面一样//connect(m_btn, &QPushButton::clicked, this, &SubWidget::showMainWidget);
}
  • 运行结果
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/154079.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx配置实例-负载均衡

1 实现效果&#xff1a; 浏览器访问nginx&#xff0c;输入访问nginx地址&#xff0c;然后负载均衡到tomcat8080和8002端口中 2 准备工作&#xff1a; 1&#xff09;准备两台tomcat容器&#xff0c;一台8080&#xff0c;一台8081 2&#xff09;在两台tomcat里面的webapps目录…

Eclipse iceoryx(千字自传)

1 在固定时间内实现无任何限制的数据传输 在汽车automotive、机器人robotics和游戏gaming等领域,必须在系统的不同部分之间传输大量数据。使用Linux等操作系统时,必须使用进程间通信(IPC)机制传输数据。Eclipse iceoryx是一种中间件,它使用零拷贝Zero-Copy、共享内存Share…

【轻松玩转MacOS】网络连接篇

引言 本篇让我们来聊聊网络连接。不论你是在家、在办公室&#xff0c;还是咖啡厅、机场&#xff0c;几乎所有的MacOS用户都需要连接到互联网。在这个部分&#xff0c;我们将向你展示如何连接到互联网和局域网。让我们开始吧&#xff01; 一、连接到互联网 首先&#xff0c;我…

http协议总结

一、http协议。 HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种在Web中广泛使用的应用层协议&#xff0c;它定义了客户端和服务器之间的通信规则&#xff0c;简化了Web应用程序的开发和交互过程。其实传输是由TCP协议完成的。 HT…

UOS通过GPG对文件签名验签

本人用的版本&#xff1a;gpg (GnuPG) 2.2.12 生成密钥 生成公钥/私钥对 gpg --full-generate-key设置密钥的长度 默认回车3072&#xff0c;越长越安全。 设定密钥的有效期限 默认回车“0” 构建用户标识 输入姓名、邮件、注释后&#xff0c;输入“o”确认 在弹出框内…

vue3学习(一)---新特性

文章目录 vue3和vue2的区别重写双向数据绑定优化Vdom性能瓶颈patch flag 优化静态树 FragmentTree shaking组合式API写法 vue3和vue2的区别 重写双向数据绑定 vue2 基于Object.defineProperty()实现vue3 基于Proxy proxy与Object.defineProperty(obj, prop, desc)方式相比有以…

OpenCV级联分类器识别车辆实践笔记

1. OpenCV 级联分类器的基本原理 基于Haar特征的级联分类器的目标检测是Paul Viola和Michael Jones在2001年的论文中提出的一种有效的目标检测方法。这是一种基于机器学习的方法&#xff0c;从大量的正面和负面图像中训练级联函数。然后用它来检测其他图像中的物体。 Haar特征…

八大排序详解(默认升序)

一、直接插入排序 直接插入排序&#xff1a;直接插入排序就是像打扑克牌一样&#xff0c;每张牌依次与前面的牌比较&#xff0c;遇到比自己大的就将大的牌挪到后面&#xff0c;遇到比自己小的就把自己放在它后面(如果自己最小就放在第一位)&#xff0c;所有牌排一遍后就完成了排…

轻松驾驭Hive数仓,数据分析从未如此简单!

1 前言 先通过SparkSession read API从分布式文件系统创建DataFrame 然后&#xff0c;创建临时表并使用SQL或直接使用DataFrame API&#xff0c;进行数据转换、过滤、聚合等操作 最后&#xff0c;再用SparkSession的write API把计算结果写回分布式文件系统 直接与文件系统交…

基于三平面映射的地形纹理化【Triplanar Mapping】

你可能遇到过这样的地形&#xff1a;悬崖陡峭的一侧的纹理拉伸得如此之大&#xff0c;以至于看起来不切实际。 也许你有一个程序化生成的世界&#xff0c;你无法对其进行 UV 展开和纹理处理。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 三平面映射&#xff08;Trip…

CTF之CTF(夺旗赛)介绍

什么是CTF&#xff1f; CTF&#xff08;Capture The Flag&#xff0c;中文一般译作“夺旗赛”&#xff09;在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式。CTF起源于1996年DEFCON全球黑客大会&#xff0c;用以代替之前黑客们通过互相发起真实攻击进行…

2023年中国全固态电池市场发展趋势分析:全固态电池的渗透率将占据固态电池市场主体[图]

全固态电池是锂电池的一种细分&#xff0c;其电池的电解质和电极材料全部由固态材料构成&#xff0c;而非传统电池中常见的液态或者凝胶电解质。由于传统液态锂电池中电解液具有易燃特性&#xff0c;近年来相关安全事故频发&#xff0c;因此随着技术革新&#xff0c;固态电池的…

openGauss学习笔记-95 openGauss 数据库管理-访问外部数据库-postgres_fdw

文章目录 openGauss学习笔记-95 openGauss 数据库管理-访问外部数据库-postgres_fdw95.1 使用postgres_fdw95.2 postgres_fdw下推主要成分95.3 常见问题95.4 注意事项 openGauss学习笔记-95 openGauss 数据库管理-访问外部数据库-postgres_fdw openGauss的fdw实现的功能是各个…

[羊城杯 2020]black cat - 文件隐写+RCE(hash_hmac绕过)

[羊城杯 2020]black cat 1 解题流程1.1 第一步1.2 第二步1.3 第三步 1 解题流程 1.1 第一步 打开网站有首歌&#xff0c;按F12也是提示听歌&#xff0c;ctf-wscan扫描就flag.php下载歌&#xff0c;用010打开&#xff0c;发现有一段内容if(empty($_POST[Black-Cat-Sheriff]) |…

ThreeJS-3D教学五-材质

我们在ThreeJS-3D教学二&#xff1a;基础形状展示中有简单介绍过一些常用的材质&#xff0c;这次我们举例来具体看下效果&#xff1a; 代码是这样的&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">&…

【Qt】三种方式实现抽奖小游戏

简介 本文章是基本Qt与C实现一个抽奖小游戏&#xff0c;用到的知识点在此前发布的几篇文章。 下面是跳转链接&#xff1a; 【Qt控件之QLabel】用法及技巧链接&#xff1a; https://blog.csdn.net/MrHHHHHH/article/details/133691441?spm1001.2014.3001.5501 【Qt控件之QPus…

CRMEB 标准版商城系统新增主题风格颜色【超级完整教程】

一、后台 1.新增主题图片 assets/images/brown.jpg和assets/images/brownsign.png 2.修改admin/src/pages/setting/themeStyle/index.vue 3.修改admin/src/pages/marketing/sign/index.vue 4.修改admin/src/pages/system/group/visualization.vue &#xff08;第三步和第四步…

嵌入式养成计划-33--数据库-sqlite3

七十一、 数据库 71.1 数据库基本概念 数据&#xff08;Data&#xff09; 能够输入计算机并能被计算机程序识别和处理的信息集合数据库 &#xff08;Database&#xff09;数据库是在数据库管理系统管理和控制之下&#xff0c;存放在存储介质上的数据集合 常用的数据库 大型数…

MapReduce(林子雨慕课课程)

文章目录 7. MapReduce7.1 MapReduce简介7.1.1 分布式并行编程7.1.2 MapReduce模型简介 7.2 MapReduce体系结构7.3 MapReduce工作流程概述7.4 Shuffle过程原理7.5 MapReduce应用程序的执行过程7.6 WordCount实例分析7.7 MapReduce的具体应用7.8 MaReduce编程实践 7. MapReduce …

Prometheus和grafana安装配置手册

1.简介 本文档为prometheus和grafana安装配置手册&#xff0c;prometheus和grafana的内容、和操作过程&#xff0c;详细介绍了服务监控配置、dashboard配置、告警配置等操作。 2.部署说明 Prometheus基于Golang编写&#xff08;需要安装&#xff09;&#xff0c;编译后的软件…