Please nominate your Qt Champions for 2021!

Transport QVariant like QSettings does [solved]

  • Hello, cute people. This is my first post in this somewhat confusing looking forum, even though I have been using Qt for a couple of years now. If I did anything wrong, overlooked any unwritten rules, etc. ... just tell me.

    Here's the problem:
    QSettings is capable of writing all kinds of variables to e.g. an .ini file. These Variables are, as far as I can tell, handled like QVariants.
    The "string" saved by QSettings looks like a string (to the human eye), or maybe a byte array. And this string can contain whatever kind of thing I can think of (QString, int, QMap, ...).
    Here an example for a QSize: @Size(16 16)

    If I now wanted to use such a formatted string to "transport" e.g. a QMap inside a program, how could I achieve that?

    The basic goal is, and maybe neither QVariant nor QSettings are of any help here, to produce a string (char *) out of whatever Qt variable I wish - and, most importantly, reverse the whole process.
    The reason why I referred to QVariant and QSettings is that it looks like there is a mechanism like that already built into Qt, but I can't seem to find/expose and (mis-)use it.

    Any hints are highly appreciated. :)

  • Lifetime Qt Champion

    Hi and welcome to devnet,
    Indeed QSettings uses QVariants to load/store the data. The string you are seeing is "an implementation detail"

    For QMap there's a QVariantMap.

    But what you could do is implement the QDataStream operators for your class and register them with qRegisterMetaTypeStreamOperators (additionally to qRegisterMetaType). This way QVariant will call them when you create one containing your class or retrieve the data.

    Hope it helps

  • “An implementation detail”? So it is indeed non-accessible?

    The datastream won't help, I think. I do want to obtain a string, as if I wanted to use QSettings to write to a map instead of a file. Or write an .ini file without ever touching QSettings.

    I have some data that is best stored in a map at runtime, but that data is supposed to be saved and loaded again without using QSettings. Due to other reasons that map needs to be treated as a string when saved, and reconverted to a map when loaded. And since that's something QSettings knows how to do, I was hoping to use its abilities.

  • Moderators

    There is no way to do that exposed by Qt. QSettings uses a specialized private implementation to do the serialization for selected types.
    If you're interested take a look at QSettingsPrivate::variantToString in the qsettings.cpp but there's no magic really.
    It's a large switch/case that formats the output for all the types.

    The reverse is similar in QSettingsPrivate::stringToVariant - looks for @, then for type name and then parses the string accordingly.

    I'd suggest to do something similar. Shouldn't be too hard.

  • Ok, thanks for giving me a direction.

    Would there be a way of somehow accessing these functions instead of copying them? I never really broke into the "private section" of Qt, so I don't know if that's a valid option.

    EDIT: Ok, the conversion seems to be really simple, I should have thought about QDataStream in depth. I have to check whether it could cause trouble, but so far it might be a good solution to just copy parts of QSettings::variantToString().

  • I think I can continue from here. Thanks a lot for the help - even though the answer seems simple, I would have spend a lot of time finding it myself. :)

    EDIT: Here some code, mostly just copied from QSettings.cpp. Currently valid for a QVariantMap, but easily modifiable to use with every other QVariant.

    Map to Variant:
    @QMap<QString, QVariant> testMap;
    //fill the map
    QVariant v(testMap);
    QByteArray a;
    QDataStream s(&a, QIODevice::WriteOnly);
    s.setVersion(QDataStream::Qt_5_1);//QSettings is using Qt_4_0
    s << v;
    a = a.toPercentEncoding();//this I added, so the string is somewhat human readable

    QString result = QLatin1String("@Variant(");
    result += QString::fromLatin1(a.constData(), a.size());
    result += QLatin1Char(')');@

    Variant to Map:
    QByteArray a = QByteArray::fromPercentEncoding(result.toLatin1().mid(9));
    //again slight modification to reverse percentEncoding
    QDataStream stream(&a, QIODevice::ReadOnly);
    QVariant out;
    stream >> out;
    QMap<QString, QVariant> testOut = out.toMap();//the map finished its travel!

Log in to reply