当前位置: 首页 > 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开发技术 【元对象系统反射机制高级用法】 二

相关文章:

  • uniapp|实现多端图片上传、拍照上传自定义插入水印内容及拖拽自定义水印位置,实现水印相机、图片下载保存等功能
  • 网络安全之XSS漏洞
  • 边缘计算新基建:iVX 轻量生成模块的 ARM 架构突围
  • 服务器开机自启动服务
  • 【技术测评】黑龙江亿林网络「启强 Plus」服务器实测:56 核 32G 配置下的性能表现与应用场景解析
  • Kotlin扩展函数与属性实战指南:从入门到企业级应用
  • Kotlin 中的数据类型有隐式转换吗?为什么?
  • pythonocc hlr实例 deepwiki 显示隐藏线
  • 力扣刷题Day 60:全排列(46)
  • 【Prometheus+Grafana实战:搭建监控系统(含告警配置)】
  • HTTP代理的实际用处有哪些?HTTP代理强在哪里?
  • 54、C# 委托 (Delegate)
  • 专栏更新通知
  • 如何手搓一个查询天气的mcp server
  • 【全因子组及排序】2022-1-23
  • 【计算机网络】IPv6和NAT网络地址转换
  • DeepSeek R1模型已完成小版本试升级
  • jQuery和CSS3卡片列表布局特效
  • 桃黑黑反斗战
  • Spring AI 整合聊天模型之智谱AI
  • 怎么做门户网站/互联网产品推广是做什么的
  • 手机网站制作相关文章/网站应该如何进行优化
  • dede 网站地图样式/如何在手机上开自己的网站
  • 网站建设培训 ppt/怎么找到精准客户资源
  • 潜力的网站设计制作/做百度推广怎么做才能有电话
  • 像美团这种网站怎么做/产品seo是什么意思