欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-08 09:23:06
...

一、通用属性对象类

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

如何将一个对象的所有属性导出为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);
}

运行结果:
通用属性对象PropertyObject,支持所有属性导出

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);
}

运行结果:
通用属性对象PropertyObject,支持所有属性导出

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);
}

运行结果:
通用属性对象PropertyObject,支持所有属性导出

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);
}

运行结果:
通用属性对象PropertyObject,支持所有属性导出

代码地址:

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


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

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

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

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

相关标签: QT Property