Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Save QSet using QSettings

Save QSet using QSettings

Scheduled Pinned Locked Moved Unsolved General and Desktop
17 Posts 3 Posters 5.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • U Offline
    U Offline
    user4592357
    wrote on last edited by A Former User
    #1

    I need to have a list of unique strings, for which I prefer to use QSet, because I also need to do searches. However, I'd like to save this list saved in settings, i.e. use QSettings to save it. However, there's no QSet => QVariant conversion so I'm stuck.

    [Edit: code tags, typos ~~ @Wieland]

    1 Reply Last reply
    0
    • M Offline
      M Offline
      mpergand
      wrote on last edited by
      #2

      Seems to work with setValue()

      QSet<QString> set;
      QVariant var; 
      var.setValue(set);  // set -> variant
      ....
      set=var.value<QSet<QString>>(); // variant -> set
      
      1 Reply Last reply
      2
      • U Offline
        U Offline
        user4592357
        wrote on last edited by
        #3

        this is what i did:

        void Game::readSettings() {
            QSettings settings { settingsFile, QSettings::IniFormat };
            const auto usernames = settings.value("usernames");
            m_usernames = usernames.value<QSet<QString>>();
        }
        
        void Game::writeSettings() const {
            QSettings settings { settingsFile, QSettings::IniFormat };
            QVariant varUsernames;
            varUsernames.setValue(m_usernames);
            settings.setValue("usernames", varUsernames);
        }
        

        but i get runtime error on variant conversion (can't convert types)

        1 Reply Last reply
        0
        • M Offline
          M Offline
          mpergand
          wrote on last edited by
          #4

          I've got this error with QSettings:

          QVariant::save: unable to save type 'QSet<QString>' (type id: 1092).
          QVariant::load: unable to load type 1092.
          

          I have no clue unfortunately ...

          1 Reply Last reply
          0
          • U Offline
            U Offline
            user4592357
            wrote on last edited by
            #5

            i guess i'll just use QStringList...

            1 Reply Last reply
            0
            • U Offline
              U Offline
              user4592357
              wrote on last edited by
              #6

              well, and another question i have, is...

              i read the settings file from the "main" class where i have all my widgets. however, every widget has some specific properties that other widgets don't. and i want to read that property from the settings file. is it considered a good practice to read the same settings file from a few places?

              1 Reply Last reply
              0
              • M Offline
                M Offline
                mpergand
                wrote on last edited by mpergand
                #7

                Yes, it is what QSettings is made for.
                From Qt doc:

                If you use QSettings from many places in your application, 
                you might want to specify the organization name and the application name using 
                QCoreApplication::setOrganizationName() and QCoreApplication::setApplicationName(), 
                and then use the default QSettings constructor:
                
                      QCoreApplication::setOrganizationName("MySoft");
                      QCoreApplication::setOrganizationDomain("mysoft.com");
                      QCoreApplication::setApplicationName("Star Runner");
                      ...
                      QSettings settings;
                
                1 Reply Last reply
                1
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @mpergand said in Save QSet using QSettings:

                  QVariant::load: unable to load type 1092

                  You have to implement the corresponding stream operators see qRegisterMetaTypeStreamOperators

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  U 1 Reply Last reply
                  5
                  • M Offline
                    M Offline
                    mpergand
                    wrote on last edited by
                    #9

                    @SGaist
                    Yes, I supposed something like that.
                    That's strange, you can serialize a QSet as is with QDataStream, but not with QVariant !

                    1 Reply Last reply
                    0
                    • SGaistS SGaist

                      @mpergand said in Save QSet using QSettings:

                      QVariant::load: unable to load type 1092

                      You have to implement the corresponding stream operators see qRegisterMetaTypeStreamOperators

                      U Offline
                      U Offline
                      user4592357
                      wrote on last edited by user4592357
                      #10

                      @SGaist

                      thanks, that's what i needed.

                      this is how i did it. i set breakpoints to on operator << and >> to see how they work, but i can't spot the mistake. when i read the settings, i.e writeSettings() function, i get one more invalid entry read from in-stream. of course i can check its validity but i wanna understand where it comes from:

                      void HighScores::readSettings() {
                      	QSettings settings { m_sSettingsFile, QSettings::IniFormat };
                      
                      	const auto highScores = settings.value("highScores");
                      
                      	if(highScores.isValid())
                      		m_highScores = highScores.value<QVariantMultiMap_t>();
                      	else
                      		m_highScores = QVariantMultiMap_t {};
                      }
                      
                      void HighScores::writeSettings() const {
                      	QSettings settings { m_sSettingsFile, QSettings::IniFormat };
                      
                      	settings.setValue("highScores", qVariantFromValue(m_highScores));
                      }
                      
                      QDataStream &operator<<(QDataStream &out, const HighScores::QVariantMultiMap_t &mmap) {
                      	const auto mmapEnd = mmap.constEnd();
                      	for(auto it = mmap.constBegin(); it != mmapEnd; ++it)
                      		out << it.key() << it.value();
                      	return out;
                      }
                      
                      QDataStream &operator>>(QDataStream& in, HighScores::QVariantMultiMap_t& mmap) {
                      	QVariant key;
                      	QString value;
                      	while(!in.atEnd()) {
                      		in >> key >> value;
                      		mmap.insert(key, value);
                      	}
                      	return in;
                      }
                      

                      where

                      using QVariantMultiMap_t = QMultiMap<QVariant, QString>;
                      QMultiMap<QVariant, QString> m_highScores;
                      

                      i've put Q_DECLARE_METATYPE(HighScoresPage::QVariantMultiMap_t) in header file after class declaration, and qRegisterMetaTypeStreamOperators<QVariantMultiMap_t>("QVariantMultiMap_t"); in constructor

                      which part am i doing wrong?

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        mpergand
                        wrote on last edited by mpergand
                        #11

                        I found a similar topic with a clear anwser :
                        [https://forum.qt.io/topic/78161/custom-class-serialize-with-qdatastream](link url)

                        I made a test with a QSet<QString>

                        typedef QSet<QString>  QStringSet;
                        Q_DECLARE_METATYPE(QStringSet)
                        
                        int main(int argc, char *argv[])
                        {
                            qRegisterMetaTypeStreamOperators<QStringSet>("QStringSet");
                            QString home=QDir::homePath();
                            QString iniFileName="config.ini";
                            QString iniPath=home+"/"+iniFileName;
                            QSettings settings(iniPath,QSettings::IniFormat);
                        
                            QStringSet setIn;
                            QVariant varIn;
                            setIn<<"A"<<"B"<<"C";
                        
                            // save
                            varIn.setValue(setIn);
                            settings.setValue("Set",varIn);
                        
                            // load
                            QVariant varOut=settings.value("Set");
                            QStringSet setOut=varOut.value<QStringSet>();
                        
                        qDebug()<<"in "<<setIn;
                        qDebug()<<"out"<<setOut;
                        
                        return 0;
                        }
                        

                        For QSet, no << operator needed, just to declare the type.
                        All seems to work and the ini file looks good.

                        1 Reply Last reply
                        1
                        • U Offline
                          U Offline
                          user4592357
                          wrote on last edited by user4592357
                          #12

                          my code actually works, but not correctly

                          the part that goes wrong in my code is in while loop in QDataStream &operator>>(QDataStream& in, HighScores::QVariantMultiMap_t& mmap). i check the stream using

                          while(!in.atEnd()) {
                              // read from stream 
                          }
                          

                          when i have, say, 1 element in the container, the saving of it in stream is done correctly. however, when reading from the stream, the execution enter the loop one time, and then one more extra time and i get an invalid element saved in container

                          p.s.
                          i tried with QStringSet but with this things are worse, writing to settings is okay, but reading always returns QVariant::Invalid:

                          void UsernamePage::readSettings() {
                          
                          	QSettings settings { filePath, QSettings::IniFormat };
                          	const auto usernames = settings.value("usernames"); // <-- returns Invalid
                          	if(usernames.isValid())
                          		m_usernames = usernames.value<QStringSet_t>();
                          	else
                          		m_usernames = QStringSet_t {};
                          }
                          
                          void UsernamePage::writeSettings() const {
                          
                          	QSettings settings { filePath, QSettings::IniFormat };
                          	settings.setValue("usernames", qVariantFromValue(m_usernames));
                          }
                          
                          QDataStream &operator<<(QDataStream &out, const ChooseUsernamePage::QStringSet_t &sset) {
                          	const auto ssetEnd = sset.constEnd();
                          	for(auto it = sset.constBegin(); it != ssetEnd; ++it)
                          		out << *it;
                          	return out;
                          }
                          
                          QDataStream &operator>>(QDataStream &in, ChooseUsernamePage::QStringSet_t &sset) {
                          	QString username;
                          	while(!in.atEnd()) {
                          		in >> username;
                          		sset.insert(username);
                          	}
                          	return in;
                          }
                          
                          1 Reply Last reply
                          0
                          • M Offline
                            M Offline
                            mpergand
                            wrote on last edited by mpergand
                            #13

                            If you are using QSet or QMap, you don't need to implement the << operator cause it's alreday the case. You only need to declare the type.

                            Example with a QMap:

                            typedef QMap<QString,QVariant>  Map;
                            qRegisterMetaTypeStreamOperators<Map>("Map");
                            
                                Map mapIn;
                                QVariant varIn;
                                mapIn["string"]="Hello";
                                mapIn["num"]=1000;
                                // save
                                varIn.setValue(mapIn);
                                settings.setValue("Map",mapIn);
                            
                                // load
                                varOut=settings.value("Map");
                                Map mapOut=varOut.value<Map>();
                            
                            qDebug()<<"in "<<mapIn;
                            qDebug()<<"out"<<mapOut;
                            

                            Logs:

                            in  QMap(("num", QVariant(int, 1000))("string", QVariant(QString, "Hello")))
                            out QMap(("num", QVariant(int, 1000))("string", QVariant(QString, "Hello")))
                            

                            You only need to implement the stream ops for your custom classes.

                            [edit] QMap is a wrong example because it's already managed by QVariant :)

                            It's only needed fot QSet !

                            U 1 Reply Last reply
                            0
                            • M mpergand

                              If you are using QSet or QMap, you don't need to implement the << operator cause it's alreday the case. You only need to declare the type.

                              Example with a QMap:

                              typedef QMap<QString,QVariant>  Map;
                              qRegisterMetaTypeStreamOperators<Map>("Map");
                              
                                  Map mapIn;
                                  QVariant varIn;
                                  mapIn["string"]="Hello";
                                  mapIn["num"]=1000;
                                  // save
                                  varIn.setValue(mapIn);
                                  settings.setValue("Map",mapIn);
                              
                                  // load
                                  varOut=settings.value("Map");
                                  Map mapOut=varOut.value<Map>();
                              
                              qDebug()<<"in "<<mapIn;
                              qDebug()<<"out"<<mapOut;
                              

                              Logs:

                              in  QMap(("num", QVariant(int, 1000))("string", QVariant(QString, "Hello")))
                              out QMap(("num", QVariant(int, 1000))("string", QVariant(QString, "Hello")))
                              

                              You only need to implement the stream ops for your custom classes.

                              [edit] QMap is a wrong example because it's already managed by QVariant :)

                              It's only needed fot QSet !

                              U Offline
                              U Offline
                              user4592357
                              wrote on last edited by
                              #14

                              @mpergand i still get invalid qvariant :(

                              1 Reply Last reply
                              0
                              • M Offline
                                M Offline
                                mpergand
                                wrote on last edited by mpergand
                                #15

                                My Example of HighScores implementation.
                                I'm using a custom class Gamer:

                                struct Gamer
                                {
                                    QString name;
                                    int highScore;
                                
                                };
                                
                                Q_DECLARE_METATYPE(Gamer)
                                
                                QDataStream &operator<<(QDataStream &out, const Gamer &gamer) {
                                
                                    out<<gamer.name<<gamer.highScore;
                                
                                    return out;
                                }
                                
                                QDataStream &operator>>(QDataStream &in, Gamer &gamer) {
                                
                                    in>>gamer.name;
                                    in>>gamer.highScore;
                                
                                    return in;
                                }
                                // for qDebug logs
                                QDebug operator<<(QDebug debug, const Gamer &gamer)
                                {
                                    debug<<gamer.name<<", "<<gamer.highScore;
                                    return debug;
                                }
                                

                                Saving HighScores in a QList<Gamer>:

                                using  HighScores=QList<Gamer>;
                                qRegisterMetaTypeStreamOperators<HighScores>("HighScores");
                                
                                Gamer g1{"John", 1200};
                                Gamer g2{"Irvin", 2200};
                                Gamer g3{"Lisa", 2140};
                                
                                HighScores scores;
                                scores<<g1<<g2<<g3;
                                QVariant v; v.setValue(scores);
                                settings.setValue("HighScores",v);
                                
                                // load
                                 v=settings.value("HighScores");
                                scores=v.value<HighScores>();
                                qDebug()<<scores;
                                

                                Output of scores:

                                ("John", 1200, "Irvin", 2200, "Lisa", 2140)
                                
                                U 1 Reply Last reply
                                1
                                • M mpergand

                                  My Example of HighScores implementation.
                                  I'm using a custom class Gamer:

                                  struct Gamer
                                  {
                                      QString name;
                                      int highScore;
                                  
                                  };
                                  
                                  Q_DECLARE_METATYPE(Gamer)
                                  
                                  QDataStream &operator<<(QDataStream &out, const Gamer &gamer) {
                                  
                                      out<<gamer.name<<gamer.highScore;
                                  
                                      return out;
                                  }
                                  
                                  QDataStream &operator>>(QDataStream &in, Gamer &gamer) {
                                  
                                      in>>gamer.name;
                                      in>>gamer.highScore;
                                  
                                      return in;
                                  }
                                  // for qDebug logs
                                  QDebug operator<<(QDebug debug, const Gamer &gamer)
                                  {
                                      debug<<gamer.name<<", "<<gamer.highScore;
                                      return debug;
                                  }
                                  

                                  Saving HighScores in a QList<Gamer>:

                                  using  HighScores=QList<Gamer>;
                                  qRegisterMetaTypeStreamOperators<HighScores>("HighScores");
                                  
                                  Gamer g1{"John", 1200};
                                  Gamer g2{"Irvin", 2200};
                                  Gamer g3{"Lisa", 2140};
                                  
                                  HighScores scores;
                                  scores<<g1<<g2<<g3;
                                  QVariant v; v.setValue(scores);
                                  settings.setValue("HighScores",v);
                                  
                                  // load
                                   v=settings.value("HighScores");
                                  scores=v.value<HighScores>();
                                  qDebug()<<scores;
                                  

                                  Output of scores:

                                  ("John", 1200, "Irvin", 2200, "Lisa", 2140)
                                  
                                  U Offline
                                  U Offline
                                  user4592357
                                  wrote on last edited by
                                  #16

                                  @mpergand that works but something's wrong with my code i guess?

                                  1 Reply Last reply
                                  0
                                  • U Offline
                                    U Offline
                                    user4592357
                                    wrote on last edited by
                                    #17

                                    i have a deadline so for now i'll use QStringList instead of QSet<Qstring>. after it i'll (hopefully) try to find what was the problem

                                    1 Reply Last reply
                                    0

                                    • Login

                                    • Login or register to search.
                                    • First post
                                      Last post
                                    0
                                    • Categories
                                    • Recent
                                    • Tags
                                    • Popular
                                    • Users
                                    • Groups
                                    • Search
                                    • Get Qt Extensions
                                    • Unsolved