QT系列第2节 QT中元对象系统

2023-11-11

      QT是在标准C++上进行了扩展,所以就有自己的特性,其中元对象系统就是其一。元对象系统有点类似于java和go语言中的反射,让我们在编程时解决问题多了些方法和思路,关于元对象可以简单总结出以下内容项。

目录

一.元对象要点总结

二. 示例代码


一.元对象要点总结

1. QObject类是所有使用元对象系统的基类

2.在一个类private区域中声明Q_OBJECT宏,MOC(元对象编译器)为每个继承(直接或者间接)Object的类生成额外代码

3. qobject_cast:QT中的强制类型转换方法

4.属性系统 Q_PROPERTY宏定义一个返回类型为type,名称为name的属性,例如:

Q_PROPERTY(type name (...))

5.setProperty可以在运行时为对象定义一个新的属性,该属性称之为动态属性

6.Q_CLASSINFO可以增加类的附加信息,例如:Q_CLASSINFO("name", "zhangsan")

二. 示例代码

接下来用一个小demo演示一下元对象的简单应用。项目目录结构结构如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "qperson.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void onAdd();
    void onSub();
    void onMetaInfo();
    void onAgeChanged(unsigned age);
    void on_spinBoxFeMale_valueChanged(int arg1);

    void on_spinBoxMale_valueChanged(int arg1);

    void on_pushButtonMetaInfo_clicked();

    void on_pushButtonAdd_clicked();

    void on_pushButtonSub_clicked();

private:
    Ui::MainWindow *ui;
    QPerson* m_male;
    QPerson* m_feMale;
};
#endif // MAINWINDOW_H

qperson.h

#ifndef QPERSON_H
#define QPERSON_H

#include <QObject>

class QPerson : public QObject
{
    Q_OBJECT
Q_CLASSINFO("author", "Zhangsan")
Q_CLASSINFO("company", "ABC")
Q_CLASSINFO("version", "1.0.0.1")
    Q_PROPERTY(unsigned age READ age WRITE setAge NOTIFY ageChanged)
    Q_PROPERTY(QString name MEMBER m_name)
    Q_PROPERTY(int score MEMBER m_score)

public:
    explicit QPerson(QString name, QObject *parent = nullptr);
    unsigned age();
    void setAge(unsigned age);
    void ageAdd(unsigned age);
    void ageSub(unsigned age);
    QString getName();

private:
unsigned m_age = 18;
QString m_name = "lisi";
int m_score = 85;

signals:
    void ageChanged(unsigned age);

};

#endif // QPERSON_H

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QObject>
#include <QDebug>
#include <QPushButton>
#include <QLineEdit>
#include <QMetaProperty>

//元对象系统(Meta-Object System)
//QObject类是所有使用元对象系统的基类
// 在一个类private区域中声明Q_OBJECT宏
// MOC(元对象编译器)为每个继承(直接或者间接)Object的类生成额外代码

//qobject_cast:强制类型转换

//属性系统 Q_PROPERTY宏定义一个返回类型为type,名称为name的属性
//Q_PROPERTY(type name (...))

//setProperty可以在运行时为类定义一个新的属性,称之为动态属性

//类的附加信息 Q_CLASSINFO("name", "zhangsan")
//QTest* pTest = new QTest;
//qDebug << pTest->metaObject()->classInfo(0).name(); //"name"
//qDebug << pTest->metaObject()->classInfo(0).value(); //"zhangsan"


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QObject* obj = new QPushButton();
    qDebug() << obj->metaObject()->className();

    QLineEdit* edit = new QLineEdit;
    qDebug() << edit->inherits("QDebug");
    qDebug() << edit->inherits("QObject");

    m_male = new QPerson("帅男人");
    m_male->setProperty("addr", "北京");
    m_male->setProperty("income", 10000);
    m_male->setProperty("height", 180);
    connect(m_male, &QPerson::ageChanged, this, &MainWindow::onAgeChanged);

    m_feMale = new QPerson("靓女人");
    m_feMale->setProperty("addr", "上海");
    m_feMale->setProperty("income", 8000);
    m_feMale->setProperty("height", 170);
    connect(m_feMale, &QPerson::ageChanged, this, &MainWindow::onAgeChanged);

    ui->spinBoxMale->setProperty("sex", true);
    ui->spinBoxFeMale->setProperty("sex", false);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onAgeChanged(unsigned age) {
    Q_UNUSED(age)
    QPerson *person = qobject_cast<QPerson*>(sender());
    QString name = person->getName();
    unsigned page = person->age();
    QString addr = person->property("addr").toString();
    int icnome = person->property("income").toInt();
    int height = person->property("height").toInt();
    ui->plainTextEdit->appendPlainText(name + ", " + addr +
        QString::asprintf(", 年龄:%d, 收入:%d, 身高:%d", page, icnome, height));
}

void MainWindow::onAdd()
{

}

void MainWindow::onSub()
{

}

void MainWindow::onMetaInfo()
{

}

void MainWindow::on_spinBoxFeMale_valueChanged(int arg1)
{
    Q_UNUSED(arg1)
    QSpinBox *spinBox = qobject_cast<QSpinBox*>(sender());
    if (spinBox->property("sex").toBool()) { // male
        m_male->ageAdd(spinBox->value());
    }
    else { //female
        m_feMale->ageSub(spinBox->value());
    }
}


void MainWindow::on_spinBoxMale_valueChanged(int arg1)
{
    Q_UNUSED(arg1)
    QSpinBox *spinBox = qobject_cast<QSpinBox*>(sender());
    if (spinBox->property("sex").toBool()) { // male
        m_male->ageAdd(spinBox->value());
    }
    else { //female
        m_feMale->ageSub(spinBox->value());
    }
}


void MainWindow::on_pushButtonMetaInfo_clicked()
{
    ui->plainTextEdit->clear();
    ui->plainTextEdit->appendPlainText("=====显示元对象信息=====\n");
    const QMetaObject *meta = m_feMale->metaObject();
    ui->plainTextEdit->appendPlainText(QString("类名: %1\n").arg(meta->className()));
    ui->plainTextEdit->appendPlainText("property:");
    for (int i = meta->propertyOffset(); i < meta->propertyCount(); i++) {
        //QMetaProperty prop = meta;
        QMetaProperty prop = meta->property(i);
        const char *propName = prop.name();
        QString propValue = m_male->property(propName).toString();
        ui->plainTextEdit->appendPlainText(QString("属性名:%1, 属性值:%2").arg(propName).arg(propValue));
    }
    ui->plainTextEdit->appendPlainText("");
    ui->plainTextEdit->appendPlainText("classinfo:");
    for (int i = meta->classInfoOffset(); i < meta->classInfoCount(); i++) {
        QMetaClassInfo classInfo = meta->classInfo(i);
        ui->plainTextEdit->appendPlainText(QString("name: %1, value: %2").
                                           arg(classInfo.name()).arg(classInfo.value()));
    }

}


void MainWindow::on_pushButtonAdd_clicked()
{
     m_male->ageAdd(1);
}


void MainWindow::on_pushButtonSub_clicked()
{
     m_feMale->ageSub(1);
}

qperson.cpp

#include "qperson.h"

QPerson::QPerson(QString name, QObject *parent)
    : QObject{parent}
{
    m_name = name;
}

unsigned QPerson::age()
{
    return m_age;
}

void QPerson::setAge(unsigned age) {
    emit ageChanged(age);
    m_age = age;
}

void QPerson::ageAdd(unsigned age) {
    m_age += age;
    emit ageChanged(m_age);
}

void QPerson::ageSub(unsigned age) {
    m_age -= age;
    emit ageChanged(m_age);
}

QString QPerson::getName() {
    return m_name;
}

 mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>507</width>
    <height>357</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="QPlainTextEdit" name="plainTextEdit"/>
    </item>
    <item>
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <layout class="QGridLayout" name="gridLayout">
        <item row="0" column="0">
         <widget class="QLabel" name="label">
          <property name="text">
           <string>男人:</string>
          </property>
         </widget>
        </item>
        <item row="0" column="1">
         <widget class="QSpinBox" name="spinBoxMale">
          <property name="value">
           <number>20</number>
          </property>
         </widget>
        </item>
        <item row="0" column="2">
         <widget class="QPushButton" name="pushButtonAdd">
          <property name="text">
           <string>增大</string>
          </property>
         </widget>
        </item>
        <item row="1" column="0">
         <widget class="QLabel" name="label_2">
          <property name="text">
           <string>女人:</string>
          </property>
         </widget>
        </item>
        <item row="1" column="1">
         <widget class="QSpinBox" name="spinBoxFeMale">
          <property name="value">
           <number>18</number>
          </property>
         </widget>
        </item>
        <item row="1" column="2">
         <widget class="QPushButton" name="pushButtonSub">
          <property name="text">
           <string>减小</string>
          </property>
         </widget>
        </item>
       </layout>
      </item>
      <item>
       <widget class="QPushButton" name="pushButtonMetaInfo">
        <property name="text">
         <string>元对象信息</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="pushButtonClear">
        <property name="text">
         <string>清空</string>
        </property>
       </widget>
      </item>
      <item>
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>68</height>
         </size>
        </property>
       </spacer>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>507</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>pushButtonClear</sender>
   <signal>clicked()</signal>
   <receiver>plainTextEdit</receiver>
   <slot>clear()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>438</x>
     <y>73</y>
    </hint>
    <hint type="destinationlabel">
     <x>253</x>
     <y>210</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

运行效果如下:

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT系列第2节 QT中元对象系统 的相关文章

  • C++:头文件中全局函数的多重定义错误

    该函数是全局的 在头文件中定义 暂时地我想把它留在那里 头文件还构成一个具有内联函数的特定类 其中一个函数调用this全局函数 源文件不包含任何有问题的全局函数 有关错误原因的任何提示吗 如果有人感兴趣的话我可以发布代码 mainwindo
  • 右键单击 QPushButton 上的 contextMenu

    对于我的应用程序 我在 Qt Designer 中创建了一个 GUI 并将其转换为 python 2 6 代码 关于一些QPushButton 与设计器创建 我想添加右键单击上下文菜单 菜单选项取决于应用程序状态 如何实现这样的上下文菜单
  • 如何通过 Qt 创建网络服务 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • QGraphicsScene没有删除QWidget的功能

    QGraphicsScene 有一个addWidget QWidget 有函数 但是没有对应的removeWidget QWidget 它只有removeItem QGraphicsItem 如何删除 QWidget 这是一个基本示例 看看
  • 第一个随机数始终小于其余随机数

    我碰巧注意到 在 C 中 使用 std rand 方法调用的第一个随机数大多数时候都明显小于第二个随机数 关于 Qt 实现 第一个几乎总是小几个数量级 qsrand QTime currentTime msec qDebug lt lt q
  • SWI-Prolog 与 C++ 接口的问题

    我试图让 SWI Prolog 与 C 很好地配合 现在束手无策 现在 在我开始准确解释我的问题是什么之前 我想首先说明我的项目是关于什么的以及我选择了哪些工具来开发解决方案 我的教授分配给我的任务是开发一个 GUI 程序 作为 SWI p
  • 打开和关闭附加窗口 (QML)

    目前我有一个通过以下方式打开的窗口 property variant win Button id testButton MouseArea onClicked var component Qt createComponent test qm
  • QML:无法读取未定义的属性“xxx”

    ApplicationWindow id root property string rootName rootName visible true width 800 height 400 title qsTr WatchFace Maker
  • 有没有办法向 QListView 添加部分?

    我正在使用 Qt5 2 和 C 来实现一个应用程序 需要显示一个列表 其中包含类似于下面的示例图像的部分 source ngo hung com http www ngo hung com files images contact list
  • 在没有加载器的情况下实例化内联组件

    有没有办法实例化内联Component 即在同一文件中定义 而不使用Loader 我不太关心使用的性能影响Loader因为我要用很多东西污染我的文件Loader包装纸 我发现从 JavaScript 创建动态 QML 对象 http doc
  • QStyledItemDelegate 绘制自定义小部件失败

    在我的一个项目中 我使用的是QTableWidget为了显示一些复杂的计算结果 为了提高表格的可读性 我需要在单个表格单元格内显示两个对齐的值 后来我想通过使用颜色或箭头等来进一步自定义小部件 为此我源自QStyledItemDelegat
  • 如何让小部件在上下文菜单出现时接收鼠标释放事件

    在Ubuntu20 04上 当上下文菜单出现时 我无法让小部件接收鼠标释放事件 而Windows可以接收 我的pyqt版本是5 15 2 我考虑过手动发送鼠标释放事件 但我不知道当上下文菜单出现时哪些系统会收到鼠标释放事件 这样做可能会导致
  • QT:删除QGridLayout中QLabel之间的空格

    我将一些具有不同颜色的 QLabels 添加到 QGridLayout 作为 QWidget 的布局 现在我在每个 Qlabel 与下一个 Qlabel 之间有一个间距 我想将其删除 我尝试将标签的边距设置为 0 将 GridLayout
  • 使用 CMake 编译时更改头文件位置会导致缺少 vtable 错误

    对于一个大型 C 项目 我需要从 qmake 过渡到 CMake 但是在处理一个玩具示例时 我遇到了一些我不理解的行为 示例代码具有单个头文件 当该头文件移动到子目录中时 我收到 MainWindow 类缺少 vtable 的错误 CMak
  • Retina 显示屏中具有 QOpenGLWIdget 的 Qt MainWindow 显示错误大小

    我有一个 Qt 应用程序MainWindow 我嵌入一个QOpenGLWidget在里面 一切正常 直到我开始使用 Apple Retina 显示屏并在高 DPI 模式下运行我的应用程序 我的QOpenGLWidget只是它应该具有的大小的
  • 如何在Qt 5中的paintEvent上使用mouseMoveEvent?

    我是 Qt 和 c 的新手 所以我遇到了一些困难 我正在尝试创建一个小部件 它可以获取 mouseMoveEvent 位置并在鼠标位置的像素图上绘制椭圆 下面你可以看到代码 include myimage h include
  • Mac OS X 上的 Qt 字体系列和样式

    我有一个基于 Qt PyQt 的 GUI 应用程序 在 Mac OS X 和其他平台 上运行 它允许用户选择字体并具有粗体和斜体选项的复选框 在更新到新的基于 Cocoa 的 Qt 时 用户发现QFontComboBox不再显示不同的字体样
  • 如何在 Qt 应用程序中嵌入 Python 解释器?

    有没有一种简单的方法可以将 Python 解释器嵌入到 Qt 应用程序中 如果可能的话 我希望有一个跨平台的解决方案 这就是目的PythonQt http pythonqt sourceforge net 它支持 Windows Linux
  • 了解 Qt3D 创建的网格

    我创建了一个 Qt3D 网格 如下所示 Qt3DCore QEntity newEntity new Qt3DCore QEntity Qt3DExtras QConeMesh mesh new Qt3DExtras QConeMesh m
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap

随机推荐

  • 第一章 红绿灯数据采集

    第一章 红绿灯数据采集 华为hilens主控 AI实现自主导航和红绿灯控制 总章目录 第一章 Hilens红绿灯数据采集 第二章 ModelArts数据处理 第三章 ModelArts模型训练 第四章 ModelArts模型转换 第五章 H
  • 国内各大互联网公司技术团队站点

    利用闲暇时间整理了一份国内各大互联网公司的相关技术站点 希望能够对大家有所帮助 也欢迎各位帮忙补充 1 腾讯系列 名称 地址 财付通设计中心TID 地址 fitdesign tencent com QQ邮箱博客 地址 blog mail q
  • 使用linux服务器相关命令

    最近需要在云GPU服务器上跑模型 初次接触这样的形式 因此记录一下比较常用的命令 一 ssh登陆指令 1 常见登陆方式 ssh 用户名 服务器ip 2 有端口号和用户名的登陆方式 ssh l 用户名 服务器ip p 端口号 二 scp指令
  • git push遇到503错误的解决方案:The requested URL returned error: 503

    git remote set url origin https your user name github com your user name your project name git 参考了这个blog https www shuiz
  • 球谐函数在环境光照中的使用原理

    在三维空间中如何对场景光照进行球谐函数展开 图形学论文解析与复现 Spherical Harmonic Lighting The Gritty Details 首先 对场景中某像素点的漫反射光照进行计算 L p w
  • 机房 机柜的保养 和清理

    https www linuxprobe com clear idc html
  • 取消Allegro的PCB文件在Drill Legend后产生的过孔标注的方法

    在cadence的PCB编辑完成后 Drill Legend生产钻孔说明表 程序会自动加上钻孔的标注 如图 给后续的再次编辑带来困扰 关闭方法 关闭图层Manufacturing gt Ncdrill Figure即可关闭钻孔标注
  • float取小数点后几位_float类型的存储方式

    在c语言中float函数是单精度的 它在内存中以二进制的形式存储 分为符号位 阶码与尾数三部分 符号位最为简单 如果你存储的是正数那么符号数就是0 如果是负数 则为1 下面 我以13 625为例说明阶码与尾数的表示方法 首先 我们取出13
  • 深入理解程序设计使用linux汇编语言(一)

    在编译运行第四章power函数遇到报错 报错信息Invalid SP address 0xffffdf2c 通过gdb定位到程序 gt 0x40007e
  • mysql数据库,oracle数据库中对字段的拼接方法

    mysql数据库 oracle数据库中对字段的拼接方法 1 简介 在日常开发中 常常有将多个字段拼接进行sql操作的场景 比如做模糊查询 我这里分两种环境阐述 1 在数据库中的写法 2 在mybatis或mybatisplus中的写法 2
  • Matlab绘图-详细全面(图)

    Matlab绘图 强大的绘图功能是Matlab的特点之一 Matlab提供了一系列的绘图函数 用户不需要过多的考虑绘图的细节 只需要给出一些基本参数就能得到所需图形 这类函数称为高层绘图函数 此外 Matlab还提供了直接对图形句柄进行操作
  • 自动驾驶(五十三)---------浅析深度学习与自动驾驶

    之前有分析过深度学习和自动驾驶的关系 但是主要是在视觉的基础上来分析的 连接 这里想从各个角度来分析深度学习在自动驾驶中的应用 如果你正好有这方面的需要 不妨选择一个着力点 笔者从事自动驾驶3年来 也处于瓶颈期 需要在一个特定的领域深挖 这
  • 华为OD机试真题-最大花费金额-2023年OD统一考试(B卷)

    题目描述 双十一众多商品进行打折销售 小明想购买自己心仪的一些物品 但由于受购买资金限制 所以他决定从众多心仪商品中购买三件 而且想尽可能的花完资金 现在请你设计一个程序帮助小明计算尽可能花费的最大资金数额 输入描述 输入第一行为一维整型数
  • 区块链技术生态的设计

    区块链技术生态的设计 详见 区块链技术生态
  • String-字符串替换

    例子 原始字符串 String demo aback 文章目录 一 replace 字符或者字符串替换 1 使用方法 2 源码 二 replaceAll 多个正则替换 1 使用方法 2 源码 三 replaceFirst 首次出现替换 1
  • 移动端兼容宝典大全,专治各种不适

    古人学问遗无力 少壮功夫老始成 移动端兼容宝典大全 专治各种不适 你是否也曾为浏览器各种的不兼容而苦恼 尤其是IE这个牛皮癣 这篇文章可能会给你帮助哦 常码字不易 出精品更难 没有特别幸运 那么请先特别努力 别因为懒惰而失败 还矫情地将原因
  • 小程序调整文章正文样式:

    1 官网地址 npm install github markdown css 2 案例 右键 gt 另存为 gt 导入 使用css文件 引入的css已markdown body的class名开头 适配时禁止github markdown转换
  • Openlayers API-Select点击要素图层

    Select是交互事件中的一种 用于选择矢量图层上的几何图形 添加选择交互事件后 点击地图上的几何图形或者将鼠标移动到几何图形上时 将获取到几何图形的相关信息 我们可以将选择的几何图形进行高亮显示 使用起来很简单 首先创建一个Select对
  • Xcode MacOS与clang c++版本关系

    关于clang https en wikipedia org wiki Clang 7 September 2017 Clang 5 0 0 released 19 January 2018 Clang becomes default co
  • QT系列第2节 QT中元对象系统

    QT是在标准C 上进行了扩展 所以就有自己的特性 其中元对象系统就是其一 元对象系统有点类似于java和go语言中的反射 让我们在编程时解决问题多了些方法和思路 关于元对象可以简单总结出以下内容项 目录 一 元对象要点总结 二 示例代码 一