当前位置: 首页 > news >正文

QT开发技术 【元对象系统反射机制 】三

Qt 元对象系统原理
Qt 的元对象系统基于三个主要元素:

QObject 基类:所有需要使用元对象系统的类都必须继承自 QObject。QObject 类提供了元对象系统的基础支持,包括信号与槽机制、事件处理等。
Q_OBJECT 宏:在类的定义中使用 Q_OBJECT 宏,它会在编译时自动生成元对象信息,这些信息包含了类的名称、属性、方法、信号和槽等。
元对象编译器(MOC):Qt 的元对象编译器(Meta-Object Compiler)会在编译前对包含 Q_OBJECT 宏的源文件进行预处理,生成额外的 C++ 代码,这些代码包含了元对象信息和实现反射功能的基础。
重要函数解析

1. QMetaObject::className()

const char *QMetaObject::className() const

该函数用于返回元对象所属类的名称。它是一个常量成员函数,不接受任何参数,返回一个指向以空字符结尾的字符串的指针。

示例代码:

#include <QObject>
#include <QDebug>class MyClass : public QObject
{Q_OBJECT
public:explicit MyClass(QObject *parent = nullptr) : QObject(parent) {}
};#include "main.moc"int main()
{MyClass obj;const QMetaObject *metaObject = obj.metaObject();qDebug() << "Class name:" << metaObject->className();return 0;
}

解释:在上述代码中,首先定义了一个继承自 QObject 的 MyClass 类,并使用 Q_OBJECT 宏。在 main 函数中,通过 metaObject() 函数获取 MyClass 对象的元对象,然后调用 className() 函数输出类的名称。

2. QMetaObject::indexOfMethod()

int QMetaObject::indexOfMethod(const char *method) const

该函数用于查找指定方法在元对象中的索引。参数 method 是一个以空字符结尾的字符串,表示要查找的方法的签名,包括方法名和参数类型。如果找到该方法,则返回其索引;否则返回 -1。

示例代码:

#include <QObject>
#include <QDebug>class MyClass : public QObject
{Q_OBJECT
public slots:void myMethod(int value) {}
public:explicit MyClass(QObject *parent = nullptr) : QObject(parent) {}
};#include "main.moc"int main()
{MyClass obj;const QMetaObject *metaObject = obj.metaObject();int methodIndex = metaObject->indexOfMethod("myMethod(int)");if (methodIndex != -1) {qDebug() << "Method found at index:" << methodIndex;} else {qDebug() << "Method not found";}return 0;
}

解释:在这个示例中,MyClass 类定义了一个槽函数 myMethod(int)。在 main 函数中,通过 indexOfMethod() 函数查找该方法的索引,并根据返回值判断方法是否存在。

3. QMetaObject::method()

QMetaMethod QMetaObject::method(int index) const

该函数用于根据索引获取元对象中的方法。参数 index 是要获取的方法的索引,通过 indexOfMethod() 函数可以得到该索引。函数返回一个 QMetaMethod 对象,该对象封装了方法的信息,包括方法名、参数类型、返回值类型等。

示例代码:

#include <QObject>
#include <QDebug>class MyClass : public QObject
{Q_OBJECT
public slots:void myMethod(int value) {}
public:explicit MyClass(QObject *parent = nullptr) : QObject(parent) {}
};#include "main.moc"int main()
{MyClass obj;const QMetaObject *metaObject = obj.metaObject();int methodIndex = metaObject->indexOfMethod("myMethod(int)");if (methodIndex != -1) {QMetaMethod method = metaObject->method(methodIndex);qDebug() << "Method name:" << method.name();} else {qDebug() << "Method not found";}return 0;
}

解释:在上述代码中,首先通过 indexOfMethod() 函数获取 myMethod(int) 方法的索引,然后使用 method() 函数根据该索引获取 QMetaMethod 对象,最后输出方法的名称。

4. QMetaMethod::invoke()

bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(nullptr), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) const

该函数用于在运行时调用指定对象的方法。参数 obj 是要调用方法的对象指针;type 是连接类型,通常使用 Qt::DirectConnection 进行直接调用;ret 用于接收方法的返回值(如果有);后续的 QGenericArgument 参数用于传递方法的参数。

示例代码:

#include <QObject>
#include <QDebug>class MyClass : public QObject
{Q_OBJECT
public slots:int myMethod(int value) {return value * 2;}
public:explicit MyClass(QObject *parent = nullptr) : QObject(parent) {}
};#include "main.moc"int main()
{MyClass obj;const QMetaObject *metaObject = obj.metaObject();int methodIndex = metaObject->indexOfMethod("myMethod(int)");if (methodIndex != -1) {QMetaMethod method = metaObject->method(methodIndex);int result;bool success = method.invoke(&obj, Qt::DirectConnection, Q_RETURN_ARG(int, result), Q_ARG(int, 5));if (success) {qDebug() << "Method invoked successfully. Result:" << result;} else {qDebug() << "Method invocation failed";}} else {qDebug() << "Method not found";}return 0;
}

解释:在这个示例中,MyClass 类的 myMethod(int) 方法返回传入参数的两倍。在 main 函数中,通过反射机制调用该方法,并将参数 5 传递给它,最后输出方法的返回值。

5. QMetaObject::indexOfProperty()

int QMetaObject::indexOfProperty(const char *name) const

该函数用于查找指定属性在元对象中的索引。参数 name 是要查找的属性的名称。如果找到该属性,则返回其索引;否则返回 -1。

示例代码:

#include <QObject>
#include <QDebug>class MyClass : public QObject
{Q_OBJECTQ_PROPERTY(int myProperty READ getMyProperty WRITE setMyProperty)
public:explicit MyClass(QObject *parent = nullptr) : QObject(parent), m_myProperty(0) {}int getMyProperty() const { return m_myProperty; }void setMyProperty(int value) { m_myProperty = value; }
private:int m_myProperty;
};#include "main.moc"int main()
{MyClass obj;const QMetaObject *metaObject = obj.metaObject();int propertyIndex = metaObject->indexOfProperty("myProperty");if (propertyIndex != -1) {qDebug() << "Property found at index:" << propertyIndex;} else {qDebug() << "Property not found";}return 0;
}

解释:在上述代码中,MyClass 类定义了一个属性 myProperty。在 main 函数中,通过 indexOfProperty() 函数查找该属性的索引,并根据返回值判断属性是否存在。

6. QMetaObject::property()

QMetaProperty QMetaObject::property(int index) const

该函数用于根据索引获取元对象中的属性。参数 index 是要获取的属性的索引,通过 indexOfProperty() 函数可以得到该索引。函数返回一个 QMetaProperty 对象,该对象封装了属性的信息,包括属性名、类型、读写权限等。

示例代码:

#include <QObject>
#include <QDebug>class MyClass : public QObject
{Q_OBJECTQ_PROPERTY(int myProperty READ getMyProperty WRITE setMyProperty)
public:explicit MyClass(QObject *parent = nullptr) : QObject(parent), m_myProperty(0) {}int getMyProperty() const { return m_myProperty; }void setMyProperty(int value) { m_myProperty = value; }
private:int m_myProperty;
};#include "main.moc"int main()
{MyClass obj;const QMetaObject *metaObject = obj.metaObject();int propertyIndex = metaObject->indexOfProperty("myProperty");if (propertyIndex != -1) {QMetaProperty property = metaObject->property(propertyIndex);qDebug() << "Property name:" << property.name();} else {qDebug() << "Property not found";}return 0;
}

解释:在这个示例中,首先通过 indexOfProperty() 函数获取 myProperty 属性的索引,然后使用 property() 函数根据该索引获取 QMetaProperty 对象,最后输出属性的名称。

一、实现根据xml文件创建界面点击切换

通过反射获取xml文件中通道号

在这里插入图片描述

三、类和xml文件准备

#ifndef YKINSWIDGET_H
#define YKINSWIDGET_H#include <QWidget>namespace Ui {
class CYKInsWidget;
}class CYKInsWidget : public QWidget
{Q_OBJECTpublic:Q_INVOKABLE explicit CYKInsWidget(QWidget *parent = nullptr);~CYKInsWidget();Q_INVOKABLE void SetChannleNo(int nChannleNo);private:Ui::CYKInsWidget *ui;int m_nChannleNo;
};#endif // YKINSWIDGET_H#include "YKInsWidget.h"
#include "ui_YKInsWidget.h"CYKInsWidget::CYKInsWidget(QWidget *parent) :QWidget(parent),ui(new Ui::CYKInsWidget)
{ui->setupUi(this);m_nChannleNo = 0;
}CYKInsWidget::~CYKInsWidget()
{delete ui;
}void CYKInsWidget::SetChannleNo(int nChannleNo)
{m_nChannleNo = nChannleNo;ui->lineEdit->setText(QString::number(m_nChannleNo));
}
<?xml version="1.0" encoding="utf-8"?>
<treewidget name="主界面树" ReflectClass="CPageTreeBase"><OneLevelItem name="通信配置" ReflectClass="CCommunConfigWidget"/><OneLevelItem name="地检测试" ReflectClass=""><TwoLevelItem name="任意遥控帧列表" ReflectClass="CYKInsWidget" ChannelNo="1"/></OneLevelItem>
</treewidget>

三、元对象反射获取函数指针核心代码以及解释

QString qstrChannelNo = element.attribute("ChannelNo");int methodIndex = metaObject->indexOfMethod("SetChannleNo(int)");if (methodIndex != -1){QMetaMethod method = metaObject->method(methodIndex);bool ok;int channelNo = qstrChannelNo.toInt(&ok);if (ok){// 调用 SetChannleNo 函数method.invoke(widget, Qt::DirectConnection, Q_ARG(int, channelNo));}}

1.获取方法索引:使用 metaObject->indexOfMethod(“SetChannleNo(int)”) 来获取 SetChannleNo 函数在元对象系统中的索引。注意,函数签名需要准确匹配,包括参数类型。
2.获取元方法对象:如果方法索引不为 -1,说明找到了该函数,使用 metaObject->method(methodIndex) 获取对应的 QMetaMethod 对象。
3.调用函数:使用 QMetaMethod::invoke 函数调用 SetChannleNo 方法,传递 widget 作为调用对象,使用 Qt::DirectConnection 直接调用,同时传递 channelNo 作为参数。

上两篇链接
QT开发技术 【元对象系统对象反射】 一
QT开发技术 【元对象系统反射机制高级用法】 二

http://www.xdnf.cn/news/697771.html

相关文章:

  • 中阳视角:如何通过波动率识别市场节奏变化
  • Android Zygote通信协议深度解析
  • c++lambda表达式
  • Linux文件传输——curl命令详介
  • SAR ADC 比较器的offset 校正
  • 西门子SCL语言编写两台电机正反转控制程序,并涵盖从选型、安装到调试全过程的详细步骤指南(上)
  • vs中添加三方库的流程
  • 根据基因名称自动获取染色体上的位置
  • STM32 ADC工作原理与配置详解
  • 渐进够增强和优雅降级的区别
  • 8.5 Q1|中山大学CHARLS发文 | 甘油三酯葡萄糖-腰身高比指数与中国中老年人心血管疾病的关系
  • (8)python+ selenium自动化测试-获取当前页面的title
  • MCU与CPU时钟概念详解:从基础到面试高频问题
  • 第三届宁波技能大赛网络安全赛项样题
  • uniapp-商城-73-shop(6-商品列表,步进器添加数据到购物车,步进器数据同步(深度监听))
  • STM32定时器的死区时间(DTR)如何计算
  • Cancer Cell|从临床病例到AI空间组学 | 空间生物标志物如何精准预测HER2阳性乳腺癌ADC疗效?
  • 瑞数6代jsvmp简单分析(天津电子税x局)
  • B2146 Hermite 多项式
  • 15.为什么HashMap的容量是2的幂次方
  • 编译与链接,咕咕咕
  • 2.2 C++之循环结构
  • 弧度 = 弧长与半径的比值
  • Vitrual Studio调试windows应用程序如何打开控制台
  • 算法-背包问题
  • 火热邀测!DataWorks数据集成支持大模型AI处理
  • 让DeepSeek去除AI痕迹的指令
  • 数据库管理:探寻高效之路
  • webpack打包基本配置
  • 图像融合质量评价指标