开发者

Qt QMetaType serialization of custom types and QVariant

开发者 https://www.devze.com 2023-02-27 00:33 出处:网络
I wish to gain access to the serialization technique used by QSettings and QVariant. For example, if you create a QRect object and store it to an INI file with QSettings you get a line that looks lik开

I wish to gain access to the serialization technique used by QSettings and QVariant. For example, if you create a QRect object and store it to an INI file with QSettings you get a line that looks lik开发者_JAVA技巧e this:

value=@Rect(1 2 3 4)

Most of the standard Qt types, and custom ones, have a similar string serialization format for saving/loading. How can I do the same thing?

That is, I have a QVariant and wish to save the data it contains then later load that data back. The saved form should be textual data (like the above) to be usable in normal config files (like INI) or the registry.


Hmm, I looked at the QSettings source code and it just has hard-coded handling for some common types and then used QDataStream for the rest. That would imply there is no generic way to serialize the data in a textual form.


Qt meta-object system is able to register a large number of operators for custom types. One of them is the StreamOperator. This operator is used by QSettings to write and read QVariant in a configuration file.

So first of all, you will need to implement the two stream operators for the custom type as mentioned by @divanov

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

After that, you need to register these two operators for the custom type to the Qt meta-object system using qRegisterMetaTypeStreamOperators.

The following example describe all steps previously mentioned with the custom type Color.

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


Personally I find QVariantMap and QVariantList quite handy for these type of things. Provide convertion functions to your class/structure:

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

Save it with toVariantMap:

settings->setValue("user", user.toVariantMap());

Fetch it with fromVariantMap:

auto user = User::fromVariantMap(settings->value("user").toVariantMap());

To save list of items other than QString, QVariantList can be used:

QVariantList list;
for (int i = 0; i < m_list.size(); ++i)
    list.append(m_list[i]);
map["list"] = list;


The QDataStream class provides serialization of binary data to a QIODevice. You should implement two operators:

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

which will be responsible for serialization and de-serialization of data.

Read more about serialization in Qt

In case you are interested in textual serialization, then you should choose QTextStream as your tool. However, the most of the classes do not have operators able to handle text streams, so you will have to implement them.

0

精彩评论

暂无评论...
验证码 换一张
取 消