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

      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>

运行效果如下:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值