QMetaType序列化的自定义类型和QVariant
Qt QMetaType serialization of custom types and QVariant
我希望访问QSettings和QVariant使用的序列化技术。例如,如果您创建一个QRect对象并将其存储到带有QSettings的INI文件中,您将得到如下一行:
value=@Rect(1 2 3 4)
大多数标准Qt类型和自定义Qt类型都有类似的字符串序列化格式用于保存/加载。我怎么能做同样的事情呢?
也就是说,我有一个QVariant,并希望保存它包含的数据,然后再将该数据加载回来。保存的表单应该是文本数据(如上所述),以便在普通配置文件(如INI)或注册表中可用。
嗯,我看了QSettings
源代码,它只是硬编码处理一些常见类型,然后使用QDataStream的其余部分。这意味着没有通用的方法来序列化文本形式的数据。
Qt元对象系统能够注册大量自定义类型的操作符。其中之一是StreamOperator。QSettings使用这个操作符来在配置文件中读写QVariant
因此,首先,您需要实现@divanov 提到的自定义类型的两个流操作符。QDataStream & operator<< ( QDataStream & stream, const YourClass & yourObject );
QDataStream & operator>> ( QDataStream & stream, YourClass & yourObject );
之后,您需要为自定义类型注册这两个操作符qRegisterMetaTypeStreamOperators.
下面的示例描述前面提到的所有步骤
#include <QMetaType>
#include <QDataStream>
#include <QSettings>
#include <cassert>
// Custom type 'Color'
struct Color
{
uint8_t _red;
uint8_t _green;
uint8_t _blue;
// Stream operator used by QSettings to save a value of type Color
// to configuration file
friend QDataStream& operator<<(QDataStream& out, const Color& color)
{
out << color._red;
out << color._green;
out << color._blue;
return out;
}
// Stream operator used by QSettings to load a value of type Color
// from a configuration file
friend QDataStream& operator>>(QDataStream& in, Color& color)
{
in >> color._red;
in >> color._green;
in >> color._blue;
return in;
}
};
Q_DECLARE_METATYPE( Color )
int main(int argc, char* argv[])
{
Q_UNUSED(argc)
Q_UNUSED(argv)
// Register Color to qt meta-object system
qRegisterMetaType<Color>();
// Register its two streams operator to qt meta-object system
qRegisterMetaTypeStreamOperators<Color>();
// Test it with QSettings!
QSettings configFile("config.ini");
// Save the color
Color saveColor { 12, 13, 14 };
configFile.setValue("Color", QVariant::fromValue(saveColor));
// Load the color
Color loadColor = configFile.value("Color", QVariant()).value<Color>();
// Asserts are successful
assert(loadColor._red == 12);
assert(loadColor._green == 13);
assert(loadColor._blue == 14);
}
我个人发现QVariantMap
和QVariantList
对于这些类型的事情非常方便。为你的类/结构提供转换函数:
class User {
public:
QVariantMap toVariantMap() const {
QVariantMap map;
map["name"] = m_name;
map["reputation"] = m_reputation;
map["tags"] = m_tags;
return map;
}
static User fromVariantMap(const QVariantMap& map) {
User user;
user.m_name = map["name"].toString();
user.m_reputation = map["reputation"].toInt();
user.m_tags = map["tags"].toStringList();
return user;
}
private:
QString m_name;
int m_reputation;
QStringList m_tags;
}
保存为toVariantMap
:
settings->setValue("user", user.toVariantMap());
使用fromVariantMap
:
auto user = User::fromVariantMap(settings->value("user").toVariantMap());
要保存QString以外的项目列表,可以使用QVariantList:
QVariantList list;
for (int i = 0; i < m_list.size(); ++i)
list.append(m_list[i]);
map["list"] = list;
QDataStream类向QIODevice提供二进制数据的序列化。您应该实现两个操作符:
QDataStream & operator<< ( QDataStream & stream, const YourClass & yourObject );
QDataStream & operator>> ( QDataStream & stream, YourClass & yourObject );
负责数据的序列化和反序列化。
阅读更多关于Qt序列化的信息
如果您对文本序列化感兴趣,则应该选择QTextStream作为你的工具。但是,大多数类没有能够处理文本流的操作符,因此您必须实现它们。
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何返回 QVariant 类型数组
- 为什么 QVariant 将字符类型视为整数类型
- 带有 QVariant 和模板的变量返回类型
- C 功能指针用于将QVariant转换为{自定义类型
- 与'operator[]'不匹配(操作数类型为 'QVariant' 和"常量字符 [2]") QVariant/QVariantMap
- 给定QVariant,获取对某个类型的变量的引用
- QVariant用户类型()id
- QList 默认参数错误消息(QList 的默认参数<QVariant>具有 int 类型)
- QVariant中的自定义类型转换为空字符串
- 如何从用户类型的QVariant中获取数据
- QVariant::isNull() 和自定义类型
- QVariant强制转换为基类型
- QMetaType序列化的自定义类型和QVariant
- Qt QDbus发送自定义类型与QVariant