Qt元对象系统 day4

news2024/11/24 11:31:54

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.coloradmin.cn/o/1068605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年9月:比特币逆势崛起!全球市场暴跌中的优异表现引人瞩目!

比特币在 9 月份上涨&#xff0c;而许多传统资产遭受了重大损失&#xff0c;凸显了加密货币的多元化特性。全球市场的压力似乎源于政府债券收益率上升和油价上涨。 随着比特币链上指标在本月的改善&#xff0c;强劲的基本面发挥了关键作用。稳定币市值在去年下降后趋于稳定&am…

RDkit的安装

1.一定要以管理员模式运行anaconda 2.用Anaconda创建一个新的虚环境 conda create -n my-rdkit python3.63.(进入)虚环境 #windows conda deactivate4.安装 conda install -c rdkit rdkit # 解释: -c 是选择channels, 选择从哪里下载, 第一个rdkit是通道,第二个是我们需要的…

SaaS和CRM软件系统间的关系

CRM系统和SaaS的概念是很多企业并不熟知的&#xff0c;CRM的字眼也是在数字化转型的浪潮下才渐渐出现在大家的眼前&#xff0c;让更多人认识到数字化工具的作用&#xff0c;但你清楚CRM系统和SaaS的关系吗&#xff1f; 什么是SaaS&#xff1f;SaaS可以理解为一种服务方式。厂商…

如何做好sop流程图?sop流程图用什么软件做?

5.如何做好sop流程图&#xff1f;sop流程图用什么软件做&#xff1f; 建立标准作业程序sop已经成为企业进步和发展的必经之路&#xff0c;不过&#xff0c;很多刚刚开始着手搭建sop的企业并不知道要如何操作&#xff0c;对于如何做sop流程图、用什么软件做sop流程图等问题充满…

数据中心负载测试中常见的挑战和解决方案有哪些?

数据中心负载测试中常见的挑战一个是搭建真实的测试环境&#xff0c;需要考虑到数据中心的规模、硬件设备、网络拓扑等因素&#xff0c;以确保测试的准确性和可靠性。在进行负载测试时&#xff0c;需要合理管理资源&#xff0c;包括服务器、存储设备、网络带宽等&#xff0c;以…

Selenium进行无界面爬虫开发

在网络爬虫开发中&#xff0c;利用Selenium进行无界面浏览器自动化是一种常见且强大的技术。无界面浏览器可以模拟真实用户的行为&#xff0c;解决动态加载页面和JavaScript渲染的问题&#xff0c;给爬虫带来了更大的便利。本文将为您介绍如何利用Selenium进行无界面浏览器自动…

C++ — 指针和数组的关系?

在本文中&#xff0c;您将了解数组与指针之间的关系&#xff0c;并在程序中有效地使用它们。 指针是保存地址的变量。指针不仅可以存储单个变量的地址&#xff0c;还可以存储数组单元的地址。 看以下示例&#xff1a; int* ptr; // 定义指针变量ptr int a[5]; ptr &a[2…

关于JDK于JRE路径配置问题

今天在配置tomcat时发现&#xff0c;无法找到jre的路径&#xff0c;在网上找了半天&#xff0c;才知道&#xff0c;JDK11版本之后&#xff0c;jre的路径默认和JDK路径一致&#xff0c;JDK11之后的文件夹中不再包含jre文件夹&#xff0c;由此在配置JRE环境变量时&#xff0c;只需…

194、SpringBoot --- 下载和安装 Erlang 、 RabbitMQ

本节要点&#xff1a; 一些命令&#xff1a; 小黑窗输入&#xff1a; rabbitmq-plugins enable rabbitmq_management 启动控制台插件 rabbitmq-server 启动rabbitMQ服务器 管理员启动小黑窗&#xff1a; rabbitmq-service install 添加rabbitMQ为本地服务 启动浏览器访问 htt…

【微信小程序开发】一文学会使用CSS样式布局与美化

引言 在微信小程序开发中&#xff0c;CSS样式布局和美化是非常重要的一部分&#xff0c;它能够为小程序增添美感&#xff0c;提升用户体验。本文将介绍如何学习使用CSS进行样式布局和美化&#xff0c;同时给出代码示例&#xff0c;帮助开发者更好地掌握这一技巧。 一、CSS样式布…

基于虚拟同步发电机的光伏混合储能并网系统Simulink仿真

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【算法刷题】【反转链表】给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

题目 解决&#xff1a; import java.util.*;/** public class ListNode {* int val;* ListNode next null;* public ListNode(int val) {* this.val val;* }* }*/public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#x…

Python 绘制玫瑰花

首先需要下载 matplotlib 模块 代码源码 from matplotlib import cm import matplotlib.pyplot as plt import numpy as npfig plt.figure() ax fig.add_subplot(projection3d) [x, t] np.meshgrid(np.array(range(25)) / 24.0, np.arange(0, 575.5, 0.5) / 575 * 17 * n…

【运筹学】整数规划建模技巧

在整数规划建模中&#xff0c;经常会使用到0-1变量来辅助建模&#xff0c;将模型表述为IP模型或BIP模型&#xff0c;下面是一些常见的整数规划建模技巧 使用辅助0-1变量实现“非此即彼”约束 如下图所示&#xff0c;有两条约束&#xff0c;希望只有其中一条起到约束的作用&am…

CVE-2023-4120:百卓智能Smart多业务安全网关智能管理平台SQL注入漏洞复现

文章目录 百卓智能Smart多业务安全网关智能管理平台SQL注入CVE-2023-4120 复现0x01 前言0x02 漏洞描述0x03 影响平台0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 百卓智能Smart多业务安全网关智能管理平台SQL注入CVE-2023-4120 复现 0x01 前言 免…

漏刻有时物联网环境态势感知大数据(设备列表、动态折线图)

物联网环境下的态势感知是指对物联网环境中的各种要素进行全面、实时、准确的监测、分析和预测,以实现网络态势的全面掌握和安全威胁的及时响应和处理。具体而言,态势感知以物联网环境为基础,利用各类传感器、数据采集设备和其他相关工具,对物联网设备、资产、数据流等进行…

Windows批处理

目录 echo off&#xff1a;关闭命令的回显功能&#xff0c;这样在执行脚本时不会显示每条命令的具体执行过程。建议将此行放在批处理脚本的首行。 rem&#xff1a;用于添加注释&#xff0c;后面可以跟上注释内容。注释的作用是对脚本进行说明或提醒&#xff0c;不会被执行。 …

大数据软件项目的应用行业

大数据软件项目可以应用于各种不同的行业&#xff0c;以帮助组织更好地理解和利用其数据资产&#xff0c;从而做出更明智的决策、提高效率并推动创新。以下是一些主要行业&#xff0c;大数据软件项目可以发挥重要作用的示例&#xff0c;希望对大家有所帮助。北京木奇移动技术有…

BaseQuickAdapter触底刷新实现

触底刷新实现 使用BaseQuickAdapter&#xff0c;在适配器中实现 LoadMoreModule即可&#xff0c;如下加上即可&#xff0c;无需多写代码 以下为分页实现&#xff1a; 视图中 // 获取加载更多模块loadMoreModule blogAdapter.getLoadMoreModule();loadMoreModule.setOnLoadMo…

滴滴出行回归:应对监管风暴,放眼全球增长

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;在遭遇监管挫折和市场份额下降后&#xff0c;滴滴出行正在恢复增长势头。 &#xff08;2&#xff09;尽管竞争激烈&#xff0c;但凭借强大的品牌和先进的技术&#xff0c;滴滴出…