通用属性对象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);
}
运行结果:
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
===================================================
===================================================
业余时间不定期更新一些想法、思考文章,欢迎关注,共同探讨,沉淀技术!
上一篇: java方法