通用属性对象PropertyObject,支持所有属性导出

一、通用属性对象类

这是以前造的一个废轮子,不过需求改变,不用了,代码写好了,也不能浪费,发出来。思路可以复用。

如何将一个对象的所有属性导出为QString,并支持不同对象的层次组合。

定义一个通用的属性对象类,如下:

PropertyObject.h

#ifndef PROPERTYOBJECT_H
#define PROPERTYOBJECT_H

#include <QObject>
#include <QVariant>
#include <QDataStream>

/**
 * @brief The PropertyObject class
 * 通用属性对象
 */
class PropertyObject : public QObject
{
    Q_OBJECT
public:
    explicit PropertyObject(QObject *parent = nullptr);
    PropertyObject(const PropertyObject& obj);

    PropertyObject& operator=(const PropertyObject &obj);
    operator QVariant() const { return QVariant::fromValue(*this); }

    static void copyProperties(QObject *dst, const QObject *src);

private:
    class RegisterType
    {
    public:
        RegisterType();
    };
    static RegisterType autoRegType; ///< 实现自动注册PropertyObject类型
};
Q_DECLARE_METATYPE(PropertyObject)

QDataStream& operator<<(QDataStream &out, const PropertyObject& info);
QDataStream& operator>>(QDataStream &in, PropertyObject& info);

#endif // PROPERTYOBJECT_H

PropertyObject.cpp

#include "PropertyObject.h"

#define EQUAL_SYMBOL           "="
#define SEPARATOR_SYMBOL       ";"
#define END_SYMBOL             "$"

PropertyObject::RegisterType PropertyObject::autoRegType;

/**
 * @brief PropertyObject::PropertyObject
 * @param parent 父节点
 */
PropertyObject::PropertyObject(QObject *parent)
    : QObject(parent)
{

}

/**
 * @brief PropertyObject::PropertyObject
 * 拷贝构造函数:
 * 因为在保存此对象时,需要放入QVariant进行装箱,期间会有对象拷贝操作,
 * 然而QObject并没有拷贝构造函数,故我们继承于QObject,然后重写拷贝构造函数,
 * 完成obj对象中property的拷贝。
 * @param obj 被拷贝对象
 */
PropertyObject::PropertyObject(const PropertyObject &obj)
{
    copyProperties(this, &obj);
}

/**
 * @brief PropertyObject::operator =
 * 重载等号操作符
 * @param obj 等号右值
 * @return 等号左值引用,即当前对象引用
 */
PropertyObject &PropertyObject::operator=(const PropertyObject &obj)
{
    copyProperties(this, &obj);
    return *this;
}

/**
 * @brief PropertyObject::copyProperties
 * 拷贝属性列表
 * @param dst 目的对象
 * @param src 源对象
 */
void PropertyObject::copyProperties(QObject *dst, const QObject *src)
{
    QList<QByteArray> names = src->dynamicPropertyNames();
    for (int i = 0; i < names.size(); i++)
    {
        const char* name = names.at(i).data();
        QVariant value = src->property(name);
        dst->setProperty(name, value);
    }
}

/**
 * @brief operator <<
 * 重载插入操作符,将属性对象序列化
 * @param out 输出流
 * @param info 属性对象
 * @return 输出流引用
 */
QDataStream& operator<<(QDataStream &out, const PropertyObject& info)
{
    QList<QByteArray> properties = info.dynamicPropertyNames();
    for (int i = 0; i < properties.size(); i++)
    {
        const char* name = properties.at(i).data();
        QVariant value = info.property(name);

        out << QString(name) << QString(EQUAL_SYMBOL) << value; // 注意写入类型必须与读取类型一致
        if (i != properties.size() - 1)
        {
            out << QString(SEPARATOR_SYMBOL);
        }
        else
        {
            out << QString(END_SYMBOL);
        }
    }
    return out;
}

/**
 * @brief operator >>
 * 重载读取操作符,将输入流反序列化为属性对象
 * @param in 输入流
 * @param info 属性对象
 * @return 输入流引用
 */
QDataStream& operator>>(QDataStream &in, PropertyObject& info)
{
    QString separator;
    do //注意写入类型必须与读取类型一致
    {
        QString name;
        in >> name;

        QString equal;
        in >> equal;
        if (equal != QString(EQUAL_SYMBOL))
            break;

        QVariant value;
        in >> value;

        info.setProperty(name.toStdString().c_str(), value);

        separator.clear();
        in >> separator;
    } while (separator == QString(SEPARATOR_SYMBOL));
    return in;
}

PropertyObject::RegisterType::RegisterType()
{
    qRegisterMetaType<PropertyObject>("PropertyObject");
    qRegisterMetaTypeStreamOperators<PropertyObject>("PropertyObject");
}

其中涉及到的知识,主要是《利用Qt的QSetting类存储自定义数据类型所需准备》。

二、测试代码

ApplicationSetting类实现如下:

ApplicationSetting::ApplicationSetting()
{
    setting = new QSettings(qApp->applicationDirPath() + "/setting.ini", QSettings::IniFormat);
}

ApplicationSetting::~ApplicationSetting()
{
    delete setting;
    setting = nullptr;
}

void ApplicationSetting::setValue(const QString &key, const QVariant &value)
{
    setting->setValue(key, value);
}

QVariant ApplicationSetting::value(const QString &key, const QVariant &defaultValue) const
{
    return setting->value(key, defaultValue);
}

1. 测试写入、读取结构体对象

// 测试写入、读取结构体对象
void MainWindow::testStructObject(ApplicationSetting *setting)
{
    // 写入
    PropertyObject src;
    src.setProperty("string", "456");
    src.setProperty("int", 80);
    src.setProperty("float", 58.9);
    src.setProperty("bool", true);
    src.setProperty("QSize", QSize(20, 50));
    setting->setValue("AppAttribute/Struct", src);

    // 读取
    QVariant var = setting->value("AppAttribute/Struct");
    PropertyObject dst = var.value<PropertyObject>();
    print(&dst);
}

运行结果:
在这里插入图片描述

2. 测试写入、读取结构体下面嵌套结构体

// 测试写入、读取结构体下面嵌套结构体
void MainWindow::testNestedStructObject(ApplicationSetting *setting)
{
    // 写入
    PropertyObject src;
    src.setProperty("string", "456");
    src.setProperty("int", 80);

    PropertyObject nested;
    nested.setProperty("int", 59);
    nested.setProperty("float", 25.3);
    src.setProperty("nested", nested);

    setting->setValue("AppAttribute/NestedStruct", src);

    // 读取
    QVariant var = setting->value("AppAttribute/NestedStruct");
    PropertyObject dst = var.value<PropertyObject>();
    print(&dst);
}

运行结果:
在这里插入图片描述

3. 测试写入、读取结构体对象列表

// 测试写入、读取结构体对象列表
void MainWindow::testStructObjectList(ApplicationSetting *setting)
{
    // 写入
    PropertyObject list;

    PropertyObject member0;
    member0.setProperty("int", 23);
    member0.setProperty("float", 29.3);
    list.setProperty("member0", member0);

    PropertyObject member1;
    member1.setProperty("int", 89);
    member1.setProperty("bool", true);
    list.setProperty("member1", member1);

    PropertyObject member2;
    member2.setProperty("string", "test");
    member2.setProperty("float", 2.3);
    list.setProperty("member2", member2);

    setting->setValue("AppAttribute/List", list);

    // 读取
    QVariant var = setting->value("AppAttribute/List");
    PropertyObject dst = var.value<PropertyObject>();
    print(&dst);
}

运行结果:
在这里插入图片描述

4. 测试写入、读取结构体对象树

// 测试写入、读取结构体对象树
void MainWindow::testStructObjectTree(ApplicationSetting *setting)
{
    // 写入
    PropertyObject root;

    // item0
    PropertyObject item0;

    PropertyObject item0_0;
    item0_0.setProperty("int", 96);

    PropertyObject item0_1;
    item0_1.setProperty("int", 36);

    item0.setProperty("item0_0", item0_0);// item0添加节点0
    item0.setProperty("item0_1", item0_1);// item0添加节点1

    // item1
    PropertyObject item1;

    PropertyObject item1_0;
    item1_0.setProperty("int", 15);

    PropertyObject item1_1;
    item1_1.setProperty("int", 25);

    item1.setProperty("item1_0", item1_0);// item1添加节点0
    item1.setProperty("item1_1", item1_1);// item1添加节点1

    root.setProperty("item0", item0);// root添加节点item0
    root.setProperty("item1", item1);// root添加节点item1

    setting->setValue("AppAttribute/Tree", root);

    // 读取
    QVariant var = setting->value("AppAttribute/Tree");
    PropertyObject dst = var.value<PropertyObject>();
    print(&dst);
}

运行结果:
在这里插入图片描述

代码地址:

https://gitee.com/bailiyang/cdemo/tree/master/Qt/38QSetting/PropertyObjectSetting


===================================================

===================================================

业余时间不定期更新一些想法、思考文章,欢迎关注,共同探讨,沉淀技术!

            

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章