Storing customized class as QSettings value



  • The question is quite simple: I have a customized class and I want to save an instance of it as a value in a QSettings variable. Is this possible taking advantage of the QVariant class? Or is there, any kind of work-around to do this?

    Any hint is very welcome :)


  • Lifetime Qt Champion

    Hi,

    IIRC you have to provide the QDataStream stream operators for your custom class and register them.

    The registration must not be forgotten otherwise they won't be found when storing your data type in QSettings.



  • Sorry for my ignorance. Can you provide me some piece of code related that I can start with? Just the key lines would be enough.
    Thank you!


  • Lifetime Qt Champion

    With minimal debug operator included

    class MyClass
    {
    public:
        MyClass() : 
            MyClass(0, 0)
        {}
        MyClass(int myParameter1, int myParameter2) : 
            _myParameter1(myParameter1), 
            _myParameter2(myParameter2)
        {}
    
        void setTruc(int myParameter1) { _myParameter1 = myParameter1; }
        void setBidule(int myParameter2) { _myParameter2 = myParameter2; }
    
        int myParameter1() const { return _myParameter1; }
        int myParameter2() const { return _myParameter2; }
    
    private:
        int _myParameter1;
        int _myParameter2;
    };
    
    
    QDataStream & operator<< (QDataStream& stream, const MyClass& myClass)
    {
        stream << myClass.myParameter1()
               << myClass.myParameter2();
        return stream;
    }
    
    QDataStream & operator>> (QDataStream& stream, MyClass& myClass)
    {
        int input = 0;
        stream >> input;
        myClass.setTruc(input);
        stream >> input;
        myClass.setBidule(input);
        return stream;
    }
    
    QDebug operator<<(QDebug debug, const MyClass &myClass)
    {
        debug  << "MyClass {"
               << myClass.myParameter1()
               << myClass.myParameter2()
               << "}";
    
        return debug;
    }
    
    Q_DECLARE_METATYPE(MyClass);
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        qRegisterMetaTypeStreamOperators<MyClass>("MyClass");
        QSettings settings;
        QVariant variant = QVariant::fromValue(MyClass(12, 13));
        settings.setValue("test", variant);
    
        qDebug() << settings.value("test").value<MyClass>();
    
        return 0;
    }
    


  • Hi again,

    I am a little stuck customizing my own class from independent files (myclass.cpp, myclass.h). So right now I am not sure what parts of the code should I leave in the main.cpp and what parts should I move into the class files (i.e. the operator definitions belongs to???). I appreciate a little explanation about it.
    Thanks!


  • Lifetime Qt Champion

    Declare the stream operators in your class headers (outside of your class) and move the implementation along your class implementation. When possible it's always better to keep these related things together.



  • Ok, I think I'm very close to get my implementation working. Nevertheless, I am getting this compilation error and I don't know how to fix it.
    Mac compiler message:

    duplicate symbol __ZlsR11QDataStreamRK10TupProject in:
        main.o
        tupproject.o
    duplicate symbol __ZrsR11QDataStreamR10TupProject in:
        main.o
        tupproject.o
    duplicate symbol __Zls6QDebugRK10TupProject in:
        main.o
        tupproject.o
    ld: 3 duplicate symbols for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    Linux compiler message:

    tupproject.o: In function `operator<<(QDebug, TupProject const&)':
    tupproject.cpp:(.text+0x140): multiple definition of `operator<<(QDebug, TupProject const&)'
    main.o:main.cpp:(.text+0x70): first defined here
    tupproject.o: In function `operator<<(QDataStream&, TupProject const&)':
    tupproject.cpp:(.text+0x560): multiple definition of `operator<<(QDataStream&, TupProject const&)'
    main.o:main.cpp:(.text+0x3b0): first defined here
    tupproject.o: In function `operator>>(QDataStream&, TupProject&)':
    tupproject.cpp:(.text+0x7d0): multiple definition of `operator>>(QDataStream&, TupProject&)'
    main.o:main.cpp:(.text+0x620): first defined here
    collect2: error: ld returned 1 exit status
    Makefile:213: recipe for target 'test' failed
    make: *** [test] Error 1
    

    The problem seems to be related to my class operators definition. The funny thing is that I'm defining them just once! :S

    Here you will find the source code (zip file) of my very basic example based on yours:
    http://www.maefloresta.com/tmp/test/

    I appreciate any suggestion. Thank you!



  • Done! I could solved it! All I had to do was to move all the operators definition to the main.cpp file and now compilation is clean. Moral: never define operators in a header you have to call from several classes.
    Thanks for all! :D


  • Lifetime Qt Champion

    That's the wrong solution.

    The correct way is to move the definition in tupproject.cpp and add the declaration in tuppproject.h


  • Qt Champions 2016

    @xtingray said in Storing customized class as QSettings value:

    Moral: never define operators in a header you have to call from several classes.

    That applies to all out-of-line functions. If you want them in the header, by all means mark them as inline, so the compiler knows to duplicate the binary at every call.



  • Following your suggestion, I moved all the operators definition into tupproject.cpp and then, I added the respective declarations into tupproject.h. Now the compilation process is pretty clean, what makes me so happy understanding that the main.cpp file looked very ugly with all those operators out-of-place right there.

    Now it works, and the structure of the code is accurate. Thank you! :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.