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. QObject::setProperty and custom class
Forum Updated to NodeBB v4.3 + New Features

QObject::setProperty and custom class

Scheduled Pinned Locked Moved Unsolved General and Desktop
12 Posts 3 Posters 4.5k Views 2 Watching
  • 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.
  • P Offline
    P Offline
    Pswin
    wrote on 14 Nov 2016, 17:54 last edited by
    #1

    I have written a custom class for holding links information:

    class Link
    {
    public:
    
         ....
    
        bool operator != ( const Link& _left )
        {
            return false;
            return ( m_sHref == _left.m_sHref ) && ( m_sRel == _left.m_sRel );
        }
    private:
        QString m_sHref;
        QString m_sRel;
    };
    
    Q_DECLARE_METATYPE( Link )
    

    and I am writing a class for enterprise entities to hold data with ability to populate itself from JSON and XML:

    class EnterpriseEntity : public QObject
    {
    public:
        Q_OBJECT
    
    public:
    
        EnterpriseEntity( QObject* _parent = nullptr ) : QObject( _parent ) {}
    
        EnterpriseEntity& fromJson( const QByteArray& _json_doc )
        {
            QJsonDocument doc = QJsonDocument::fromJson( _json_doc );
    
            QJsonObject obj = doc.object();
    
            for ( QString var : obj.keys()  )
            {
                    if ( this->setProperty( var.toStdString().c_str(),  obj[var].toVariant() ) == false )
                    {
                        qDebug() << "Error in seting: " << var;
                    }
            }
    
            return *this;
        }
    }; // EnterpriseEntity
    

    and my json object is like this:

    {"family":"Kafman","id":18,"link":{"href":"http://localhost/api/users/Ema","rel":"self"},"name":"Ema"}
    

    finally I have created an User entity like this:

    class User : public EnterpriseEntity
    {
    public:
        Q_OBJECT
        Q_PROPERTY(QString name MEMBER m_sName )
        Q_PROPERTY(QString family MEMBER m_sFamily )
        Q_PROPERTY(QString id MEMBER m_iID )
        Q_PROPERTY(Link link MEMBER m_sLink )
    
    public:
        ....
    
    private:
    
        QString m_iID;
        QString m_sName;
        QString m_sFamily;
        Link m_sLink;
    }
    

    the problem is that while setProperty in EnterpriseEntity::fromJson works fine with QString, it returns false for "link". It has been for two days that I am struggling to tackle this issue yet I haven't succeeded. I would be grateful if you could help me to overcome this difficultly.

    1 Reply Last reply
    0
    • V Offline
      V Offline
      VRonin
      wrote on 14 Nov 2016, 18:09 last edited by VRonin
      #2

      link is an object, as documented here it will be converted to a QVariantMap, having href and rel as keys. There is no way for the QJasonValue::toVariant() to know that your object is a Link so it cannot possibly convert it to it.

      if you provide:

      Link::Link(const QVariantMap& val){
      m_sHref = val.value("href").toString();
      m_sRel = val.value("rel").toString();
      }
      Link& Link::operator=(const QVariantMap& val){
      m_sHref = val.value("href").toString();
      m_sRel = val.value("rel").toString();
      return *this;
      }
      

      it might work

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      0
      • P Offline
        P Offline
        Pswin
        wrote on 14 Nov 2016, 18:13 last edited by
        #3

        Actually, I have provided, but It did not work

        Link ( const QVariantMap& _map )
            {
                m_sHref = _map["href"].toString();
                m_sRel = _map["rel"].toString();
            }
        
           Link& operator= ( const QVariantMap& _map )
            {
                m_sHref = _map["href"].toString();
                m_sRel = _map["rel"].toString();
                qDebug() << "called" ;
                return *this;
            }
        
        1 Reply Last reply
        0
        • V Offline
          V Offline
          VRonin
          wrote on 14 Nov 2016, 18:18 last edited by VRonin
          #4

          could you qDebug() << obj[var].type() << " - " << obj[var].toVariant().type(); and tell us what it prints?

          I'm afraid you'll have to do it manually btw

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          0
          • P Offline
            P Offline
            Pswin
            wrote on 14 Nov 2016, 18:27 last edited by
            #5

            I have added following code to 'EnterpriseEntity::fromJson' method (in the loop):

            qDebug() << this->metaObject()->className() << var << obj[var].toVariant();
            qDebug() << obj[var].type() << " - " << obj[var].toVariant().type();
            

            and output is like that:

            User "link" QVariant(QVariantMap, QMap(("href", QVariant(QString, "http://localhost/api/users/Ema"))("rel", QVariant(QString, "self"))))
            5  -  QVariant::QVariantMap
            
            1 Reply Last reply
            0
            • V Offline
              V Offline
              VRonin
              wrote on 14 Nov 2016, 18:33 last edited by VRonin
              #6

              Then I'm afraid it's manual:

              const auto allKeys = obj.keys();
               for ( const QString& var : allKeys   ) //this is more efficient
                      {
              if(obj[var].type()==QJsonValue::Object){
              
                              if ( !setProperty( var.toLatin1().constData(), obj[var].type()==QJsonValue::Object ? QVariant(Link(obj[var].toVariant())):  obj[var].toVariant() ) )
                              {
                                  qDebug() << "Error in seting: " << var;
                              }
                      }
              

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              0
              • P Offline
                P Offline
                Pswin
                wrote on 14 Nov 2016, 18:56 last edited by
                #7

                @VRonin said in QObject::setProperty and custom class:

                Then I'm afraid it's manual:

                I hope not. It would be the worst option. In particular for big and enterprise software.

                1 Reply Last reply
                0
                • V Offline
                  V Offline
                  VRonin
                  wrote on 14 Nov 2016, 19:03 last edited by
                  #8

                  ok, last try (as I think I'm getting drunk on all these nested types)

                  Link::Link(const QVariant& vart){
                  if(vart.type()==QMetaType::QVariantMap){
                  const QVariantMap val= vart.toVariantMap();
                  m_sHref = val.value("href").toString();
                  m_sRel = val.value("rel").toString();
                  }
                  }
                  Link& Link::operator=(const QVariant& vart){
                  if(vart.type()==QMetaType::QVariantMap){
                  const QVariantMap val= vart.toVariantMap();
                  m_sHref = val.value("href").toString();
                  m_sRel = val.value("rel").toString();
                  }
                  return *this;
                  }
                  

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  1 Reply Last reply
                  0
                  • P Offline
                    P Offline
                    Pswin
                    wrote on 14 Nov 2016, 19:28 last edited by
                    #9

                    @VRonin said in QObject::setProperty and custom class:

                    ok, last try (as I think I'm getting drunk on all these nested types)

                    I had done that too :(.

                    Telling the truth, me too. however Qt is great library, it doesn't support some basic and essential classes ( and I haven't any idea why?! ).For instance, there is not any class for working with integers that could accept null values, while there are database adapters and support in it ( and it goes without saying that nullable fields are a vital part of any database design.)

                    I was about writing these classes by myself (such as Integer, etc.), nevertheless I faced to this problem.

                    this is a complete version of my Link class:

                    class Link
                    {
                    public:
                    
                        explicit Link ( );
                    
                        Link ( const Link& _link );
                    
                        Link ( const QVariant& _var );
                    
                        Link ( const QVariantMap& _map );
                    
                        operator QVariant() const;
                    
                    
                       bool operator != ( const Link& _left );
                    
                       Link& operator= ( const QVariantMap& _map );
                    
                       Link& operator= ( const QVariant& _var );
                    
                       QString getHref( void ) const { return m_sHref; }
                    
                       void setHref( const QString& _link ) { m_sHref = _link; }
                    
                       QString getRelation( void) const { return m_sRel; }
                    
                       void setRelation( const QString& _rel ) { m_sRel = _rel; }
                    
                    private:
                        QString m_sHref;
                        QString m_sRel;
                    };
                    
                    V kshegunovK 2 Replies Last reply 14 Nov 2016, 20:01
                    0
                    • P Pswin
                      14 Nov 2016, 19:28

                      @VRonin said in QObject::setProperty and custom class:

                      ok, last try (as I think I'm getting drunk on all these nested types)

                      I had done that too :(.

                      Telling the truth, me too. however Qt is great library, it doesn't support some basic and essential classes ( and I haven't any idea why?! ).For instance, there is not any class for working with integers that could accept null values, while there are database adapters and support in it ( and it goes without saying that nullable fields are a vital part of any database design.)

                      I was about writing these classes by myself (such as Integer, etc.), nevertheless I faced to this problem.

                      this is a complete version of my Link class:

                      class Link
                      {
                      public:
                      
                          explicit Link ( );
                      
                          Link ( const Link& _link );
                      
                          Link ( const QVariant& _var );
                      
                          Link ( const QVariantMap& _map );
                      
                          operator QVariant() const;
                      
                      
                         bool operator != ( const Link& _left );
                      
                         Link& operator= ( const QVariantMap& _map );
                      
                         Link& operator= ( const QVariant& _var );
                      
                         QString getHref( void ) const { return m_sHref; }
                      
                         void setHref( const QString& _link ) { m_sHref = _link; }
                      
                         QString getRelation( void) const { return m_sRel; }
                      
                         void setRelation( const QString& _rel ) { m_sRel = _rel; }
                      
                      private:
                          QString m_sHref;
                          QString m_sRel;
                      };
                      
                      V Offline
                      V Offline
                      VRonin
                      wrote on 14 Nov 2016, 20:01 last edited by VRonin
                      #10

                      could you try to implement an explicit reader and writer for the function? it might be that in that case implicit conversion is executed (so keep that QVariant constructor):

                      It is manual :(

                      @Pswin said in QObject::setProperty and custom class:

                      it doesn't support some basic and essential classes

                      Let's be honest, this is far from essential, you are just trying to find a lazy solution that saves you checking what var contains. an if on it solves your problem straight away

                      P.S.
                      @Pswin said in QObject::setProperty and custom class:

                      integers that could accept null values

                      That's actually very easy to implement using pointers (or smart pointers):

                      std::unique_ptr<int> nullableInt; //start with a null int
                      
                      if(nullableInt)
                      qDebug() << "int is valid, value: " << *nullableInt;
                      else
                      qDebug("int is null");
                      
                      nullableInt = std::make_unique<int>(3); // set it to 3
                      
                      if(nullableInt)
                      qDebug() << "int is valid, value: " << *nullableInt;
                      else
                      qDebug("int is null");
                      
                      nullableInt.reset(); //set it back to null
                      
                      if(nullableInt)
                      qDebug() << "int is valid, value: " << *nullableInt;
                      else
                      qDebug("int is null");
                      

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      P 1 Reply Last reply 14 Nov 2016, 20:50
                      1
                      • V VRonin
                        14 Nov 2016, 20:01

                        could you try to implement an explicit reader and writer for the function? it might be that in that case implicit conversion is executed (so keep that QVariant constructor):

                        It is manual :(

                        @Pswin said in QObject::setProperty and custom class:

                        it doesn't support some basic and essential classes

                        Let's be honest, this is far from essential, you are just trying to find a lazy solution that saves you checking what var contains. an if on it solves your problem straight away

                        P.S.
                        @Pswin said in QObject::setProperty and custom class:

                        integers that could accept null values

                        That's actually very easy to implement using pointers (or smart pointers):

                        std::unique_ptr<int> nullableInt; //start with a null int
                        
                        if(nullableInt)
                        qDebug() << "int is valid, value: " << *nullableInt;
                        else
                        qDebug("int is null");
                        
                        nullableInt = std::make_unique<int>(3); // set it to 3
                        
                        if(nullableInt)
                        qDebug() << "int is valid, value: " << *nullableInt;
                        else
                        qDebug("int is null");
                        
                        nullableInt.reset(); //set it back to null
                        
                        if(nullableInt)
                        qDebug() << "int is valid, value: " << *nullableInt;
                        else
                        qDebug("int is null");
                        
                        P Offline
                        P Offline
                        Pswin
                        wrote on 14 Nov 2016, 20:50 last edited by
                        #11

                        @VRonin

                        Using 'Boost.Optional' would be better option:

                        http://www.boost.org/doc/libs/1_47_0/libs/optional/doc/html/index.html

                        like:

                        boost::optional<int> m_iID;
                        

                        Honestly, As I am developing a large scale application, I am looking for ways that are not error prone. Checking members manually again and again in every class makes software more liable for bugs and harder to control and revise. As result, such class are essential to me (at least).

                        1 Reply Last reply
                        0
                        • P Pswin
                          14 Nov 2016, 19:28

                          @VRonin said in QObject::setProperty and custom class:

                          ok, last try (as I think I'm getting drunk on all these nested types)

                          I had done that too :(.

                          Telling the truth, me too. however Qt is great library, it doesn't support some basic and essential classes ( and I haven't any idea why?! ).For instance, there is not any class for working with integers that could accept null values, while there are database adapters and support in it ( and it goes without saying that nullable fields are a vital part of any database design.)

                          I was about writing these classes by myself (such as Integer, etc.), nevertheless I faced to this problem.

                          this is a complete version of my Link class:

                          class Link
                          {
                          public:
                          
                              explicit Link ( );
                          
                              Link ( const Link& _link );
                          
                              Link ( const QVariant& _var );
                          
                              Link ( const QVariantMap& _map );
                          
                              operator QVariant() const;
                          
                          
                             bool operator != ( const Link& _left );
                          
                             Link& operator= ( const QVariantMap& _map );
                          
                             Link& operator= ( const QVariant& _var );
                          
                             QString getHref( void ) const { return m_sHref; }
                          
                             void setHref( const QString& _link ) { m_sHref = _link; }
                          
                             QString getRelation( void) const { return m_sRel; }
                          
                             void setRelation( const QString& _rel ) { m_sRel = _rel; }
                          
                          private:
                              QString m_sHref;
                              QString m_sRel;
                          };
                          
                          kshegunovK Offline
                          kshegunovK Offline
                          kshegunov
                          Moderators
                          wrote on 14 Nov 2016, 21:21 last edited by kshegunov
                          #12

                          @Pswin said in QObject::setProperty and custom class:

                          For instance, there is not any class for working with integers that could accept null values

                          This makes no sense at all. There's no null semantics put into integers, that's a db thing and C++ has no notion of it. As such the ambiguity is wrapped in QVariant (which wraps around a union) as it should. QVariant::isNull is probably what you're expecting to find.

                          @VRonin said in QObject::setProperty and custom class:

                          That's actually very easy to implement using pointers (or smart pointers)

                          Oh, come on Luca, are we going to start creating individual characters in the heap next?
                          Here's how it could be done the right way (which QVariant already does internally):

                          struct SpecialValue
                          {
                              enum SupportedTypes { NullType, IntType, DoubleType };
                          
                              SupportedTypes type;  // Contains the type currently set (the active field in the union)
                              union  {
                                  int intValue;
                                  double doubleValue;
                              } data;  // The data
                          };
                          

                          @Pswin

                          What you probably want to implement is an interface that will abstract the streaming from and to a JsonObject and all objects that implement that would call each of their properties that implement it to serialize themselves. Then the other way around is exactly the same. E.g. (I leave the serialization to your imagination):

                          class JsonSerializable
                          {
                          public:
                              virtual QJsonObject toJsonObject() const = 0;
                              virtual void fromJsonObject(const QJsonObject &) = 0;
                          };
                          
                          class EnterpriseEntity : public QObject, public JsonSerializable
                          {
                              // ...
                              void fromJsonObject(const QJsonObject & object) override
                              {
                                  // Other properties
                                  // ...
                                  // Link
                                  Link link;
                                  link.fromJsonObject(object.value("link").toObject());
                                  setProperty("link", link);
                              }
                          }
                          
                          class Link : public JsonSerializable
                          {
                          public:
                              void fromJsonObject(const QJsonObject & object) override
                              {
                                  m_sHref = object.value("href").toString();
                                  m_sRel = object.value("rel").toString();
                              }
                          };
                          

                          Read and abide by the Qt Code of Conduct

                          1 Reply Last reply
                          2

                          1/12

                          14 Nov 2016, 17:54

                          • Login

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