Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Value Stored in QSetting is not retained after the program is restarted.



  • I have a class, User class which can read from a Json object and can write to Json object. As described below.

    class User
    {
    public:
        User() {}
        User(const QString& ruser_name, const QImage& rdisplay_image)
        {
            user_name = ruser_name;
            display_image = rdisplay_image;
        }
    
        QString get_user_name() const { return user_name; }
    
        void write(QJsonObject &json) const
        {
            json["user_name"] = user_name;
            json["display_image"] = getImageInJsonValueFormat(display_image);
    
        }
    
        void read(const QJsonObject &json)
        {
            if (json.contains("user_name") && json["user_name"].isString())
                user_name = json["user_name"].toString();
    
            if (json.contains("display_image"))
                display_image = getImageFromJsonValueFormat(json["display_image"]);
        }
    private:
        QString user_name;
        QImage  display_image;
    };
    

    There are two helper functions, to convert QImage from JsonValue and vice-versa. As depicted below.

    QJsonValue getImageInJsonValueFormat(const QImage& image)
    {
        QByteArray image_ByteArray;
        if (image.isNull() != true)
        {
            QBuffer image_buffer(&image_ByteArray);
            image_buffer.open(QIODevice::WriteOnly);
            image.save(&image_buffer, "png");
            auto const encoded = image_buffer.data().toBase64();
            return {QLatin1String(encoded)};
        }
        return QLatin1String("");
    }
    
    QImage getImageFromJsonValueFormat(const QJsonValue& imageJsonValue)
    {
        QImage image;
        auto const encoded = imageJsonValue.toString().toLatin1();
        image.loadFromData(QByteArray::fromBase64(encoded), "png");
        return image;
    }
    

    I have three functions. One to build the list, another to store and last one to read. As describe below

    QMap<QString, User> Build_user_list()
    {
        QMap<QString, User> user_list;
        User User1("baur",QImage("/home/Downloads/bechambaur.png"));
        user_list["baur"] = User1;
    
        User User2("Muller",QImage("/home/Downloads/GerdMuller.png"));
        user_list["Muller"] = User2;
        return user_list;
    }
    
    void StoreUserList(const QMap<QString, User> user_list)
    {
        QJsonObject userListObject;
        QJsonArray userListArray;
    
        QMapIterator<QString,User> iterator(user_list);
    
        while (iterator.hasNext())
        {
            iterator.next();
            QJsonObject userJsonObject;
            User userObj = iterator.value();
            userObj.write(userJsonObject);
            userListArray.append(userJsonObject);
        }
        userListObject["user_list"] = userListArray;
        QJsonDocument userListDoc(userListObject);
    
        QSettings user_settings;
    
        user_settings.setValue("QSettingsApplication", userListDoc);
        user_settings.sync();
    }
    
    QMap<QString, User> GetStoredList()
    {
        QMap<QString, User> user_list;
        QSettings user_settings;
        QJsonDocument userListDocRead = user_settings.value("QSettingsApplication", "").toJsonDocument();
        QJsonObject userListObjectRead = userListDocRead.object();//["userlist"];
    
        if (userListObjectRead.contains("user_list"))
        {
            if(userListObjectRead["user_list"].isArray())
            {
                QJsonArray userlistarray = userListObjectRead["user_list"].toArray();
                user_list.clear();
                for(int index = 0; index < userlistarray.size(); ++index)
                {
                    QJsonObject json_user_object = userlistarray[index].toObject();
                    User userObject;
                    userObject.read(json_user_object);
                    user_list[userObject.get_user_name()] = userObject;
                }
            }
        }
    
        return user_list;
    }
    

    In below piece of code (assuming the application is running for the first time), first call to GetStoredList results in an empty map. Later, default map is created and stored. Again GetStoredList is called, this sucessfully populates the values. However, if the application is closed and ran again, call to GetStoredList returns empty map. I expect this to fill with two objects. Whats wrong?

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        // Why below list is empty after first successful run?
        QMap<QString, User> user_listRead = GetStoredList();
    
        if (user_listRead.size() == 0)
        {
            QMap<QString, User> user_list = Build_user_list();
            StoreUserList(user_list);
            QMap<QString, User> user_listRead = GetStoredList();
            user_listRead = GetStoredList();
            // This is is not empty, it reads contents successfully. What's wrong?
        }
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    


  • @Joshi
    Unless I am completely mad, I don't see where you think you are persisting the settings to/from external storage (.ini file, registry, whatever)? Your new QSettings() is "anonymous", no file/registry?



  • Thanks for response.
    I must have been more explicit in my first post. I am running this application in Ubuntu and I do not want to depend on a file location. I am more curious as to why the GetStoredList(); called second time (very independent call, everything is local to this function) reads the values successfully. Whats the difference between GetStoredList called second time in the first run and called first time in the second run?



  • I am also reading that an explicit sync of Linux is required. Looking to check where it is defined.



  • @Joshi
    One of us is getting confused!

    QMap<QString, User> user_listRead = GetStoredList();
    ...
    QMap<QString, User> user_list = Build_user_list();
    StoreUserList(user_list);
    ...
    user_listRead = GetStoredList();
    

    The first call to GetStoredList(); has nothing previously saved to read from. The second GetStoredList(); gets entries just created by the StoreUserList(user_list);.

    ?

    If you want to persist settings across application runs you have to persist them somewhere, where else do you expect Linux or whatever to retrieve them from!?

    [BTW: Your code is also leaking a couple of QSettings objects. And especially given that, you will need to either sync() or explicitly destruct to save permanently.]



  • Thanks Jon

    I made a small test, exactly the same way, but this time it is plane QString object. In below example, the first read

    QString TmpString = TempSettings.value("TempLocation","").toString();)
    
    

    returns blank string during the first run. On finding blank, it is updated with some data. Application closed and restarted. Data is persistent here. That is when running application subsequently, data in TmpString is read successfully. There is something wrong with (which I am not able to get with QJsonDocument)

    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QSettings TempSettings;
        QString TmpString = TempSettings.value("TempLocation","").toString();
        if (TmpString == "")
        {
            TempSettings.setValue("TempLocation", QString("Has this been read"));
            TempSettings.sync();
        }
    
    
        // previous code
        // Why below list is empty after first successful run?
        QMap<QString, User> user_listRead = GetStoredList();
        ...    
        return a.exec();
    }
    
    


  • @JonB , I figured out the issue, but not the solution so far. The issues lies in data transforming from QVariant into QJsondoc or QSjonObject.

    Here is the simplified version of about problem

    #include <QCoreApplication>
    #include <QString>
    #include <QJsonObject>
    #include <QBuffer>
    #include <QSettings>
    #include <QJsonArray>
    #include <QJsonDocument>
    class User
    {
    public:
        User() {}
        User(const QString& ruser_name, const int& ruser_age)
        {
            user_name = ruser_name;
            user_age = ruser_age;
        }
    
        QString get_user_name() const { return user_name; }
    
        void write(QJsonObject &json) const
        {
            json["user_name"] = user_name;
            json["user_age"] = user_age;
        }
    
        void read(const QJsonObject &json)
        {
            if (json.contains("user_name") && json["user_name"].isString())
                user_name = json["user_name"].toString();
    
            if (json.contains("user_age"))
                user_age = json["user_name"].toInt();
        }
    private:
        QString user_name;
        int user_age;
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QMap<QString, User> user_list;
        user_list["Tom"] = User("Tom",10);
        user_list["Henry"] = User("Henry",20);
    
        QJsonArray userListArray;
    
        QMapIterator<QString,User> iterator(user_list);
    
        while (iterator.hasNext())
        {
            iterator.next();
            QJsonObject userJsonObject;
            User userObj = iterator.value();
            userObj.write(userJsonObject);
            userListArray.append(userJsonObject);
        }
    
        QJsonObject user_list_object_wrote;
        user_list_object_wrote["user_list"] = userListArray;
    
        QJsonDocument user_list_doc_wrote(user_list_object_wrote);
    
        QVariant user_list_variant = user_list_doc_wrote.toVariant();
    
        // Now read the data back into QJsonDocument/QJsonObject. Below two do not get any data.
        QJsonDocument user_list_doc_read = user_list_variant.toJsonDocument();
    
        QJsonObject user_list_object_read = user_list_variant.toJsonObject();
    
        return a.exec();
    }
    
    

  • Qt Champions 2019

    @Joshi What does

    qDebug() << user_list_doc_read;
    

    tell you?



  • three debug statements
    ```
    qDebug() << "user_list_variant : <" << user_list_variant << ">" << endl;
    qDebug() << "user_list_doc_read : <" << user_list_doc_read << ">" << endl;
    qDebug() << "user_list_object_read : <" << user_list_object_read << ">" << endl;

    
    and their outputs..
    user_list_variant : < QVariant(QVariantMap, QMap(("user_list", QVariant(QVariantList, (QVariant(QVariantMap, QMap(("user_age", QVariant(double, 20))("user_name", QVariant(QString, "Henry")))), QVariant(QVariantMap, QMap(("user_age", QVariant(double, 10))("user_name", QVariant(QString, "Tom"))))))))) > 
    
    user_list_doc_read : < QJsonDocument() > 
    
    user_list_object_read : < QJsonObject() >


  • @jsulm , @JonB

    Solution found:

    QVariant::toJsonDocument does not do the opposite of QJsonDocument::toVariant.

    Instead of using QVariant::toJsonDocument, use QJsonDocument::fromVariant, static function of QJsonDocument.


Log in to reply