【问题标题】:Qt QMetaType serialization of custom types and QVariantQt QMetaType 序列化自定义类型和QVariant
【发布时间】:2011-08-09 07:05:21
【问题描述】:

我希望访问 QSettings 和 QVariant 使用的序列化技术。例如,如果您创建一个 QRect 对象并将其存储到带有 QSettings 的 INI 文件中,您会得到如下所示的一行:

value=@Rect(1 2 3 4)

大多数标准 Qt 类型和自定义类型都具有类似的用于保存/加载的字符串序列化格式。我怎样才能做同样的事情?

也就是说,我有一个 QVariant 并希望保存它包含的数据,然后稍后再加载该数据。保存的表单应该是文本数据(如上),以便在普通配置文件(如 INI)或注册表中使用。


嗯,我查看了QSettings 源代码,它只是对一些常见类型进行了硬编码处理,然后使用 QDataStream 处理其余部分。这意味着没有通用的方法来以文本形式序列化数据。

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    Qt 元对象系统能够为自定义类型注册大量运算符。其中之一是 StreamOperator。 QSettings 使用此运算符来 在配置文件中写入和读取 QVariant。

    首先,您需要为@divanov 提到的自定义类型实现两个流运算符

    QDataStream & operator<< ( QDataStream & stream, const YourClass & yourObject );
    QDataStream & operator>> ( QDataStream & stream, YourClass & yourObject );
    

    之后,需要为自定义类型注册这两个操作符 使用 qRegisterMetaTypeStreamOperators 的 Qt 元对象系统。

    以下示例描述了前面提到的所有步骤 自定义类型颜色。

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

    【讨论】:

      【解决方案2】:

      我个人觉得QVariantMapQVariantList 对于这类事情非常方便。 为您的类/结构提供转换函数:

      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;
      

      【讨论】:

        【解决方案3】:

        QDataStream 类提供二进制数据到 QIODevice 的序列化。 您应该实现两个运算符:

        QDataStream & operator<< ( QDataStream & stream, const YourClass & yourObject );
        QDataStream & operator>> ( QDataStream & stream, YourClass & yourObject );
        

        它将负责数据的序列化和反序列化。

        Read more about serialization in Qt

        如果你对文本序列化感兴趣,那么你应该选择 QTextStream 作为你的工具。但是,大多数类没有能够处理文本流的运算符,因此您必须实现它们。

        【讨论】:

        • 这会创建一个二进制流,即使对于像 QRect 这样的东西也是如此。它可以用作最终的后备,但我更喜欢为常见对象使用像 QSettings 这样的文本类型。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多