Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. can I make a temporary, local copy of a property?
Forum Updated to NodeBB v4.3 + New Features

can I make a temporary, local copy of a property?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
12 Posts 3 Posters 1.3k Views 1 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.
  • dheerendraD dheerendra

    @mzimmers

    There is no other way to do this. You need to have copy of the object with you. Either this object is created in QML or C++ side. You need to update this object & send the object to c++ side either as Q_PROPERTY or argument to server object method.

    mzimmersM Offline
    mzimmersM Offline
    mzimmers
    wrote on last edited by
    #3

    @dheerendra OK, thanks for letting me know.

    As far as implementation, I'm thinking of putting this functionality into my C++ code. But, if I create a makeCopy() function in my model, and invoke it from JS/QML, where do I need to perform the garbage collection?

    dheerendraD 1 Reply Last reply
    0
    • mzimmersM mzimmers

      @dheerendra OK, thanks for letting me know.

      As far as implementation, I'm thinking of putting this functionality into my C++ code. But, if I create a makeCopy() function in my model, and invoke it from JS/QML, where do I need to perform the garbage collection?

      dheerendraD Offline
      dheerendraD Offline
      dheerendra
      Qt Champions 2022
      wrote on last edited by
      #4

      @mzimmers

      If you have have created object in C++ & getting in qml, set the object ownership to cpp using QQMLEngine::setObjectOwnership.

      Dheerendra
      @Community Service
      Certified Qt Specialist
      http://www.pthinks.com

      GrecKoG 1 Reply Last reply
      0
      • dheerendraD dheerendra

        @mzimmers

        If you have have created object in C++ & getting in qml, set the object ownership to cpp using QQMLEngine::setObjectOwnership.

        GrecKoG Online
        GrecKoG Online
        GrecKo
        Qt Champions 2018
        wrote on last edited by
        #5

        But here the thing to do is let the QML engine have the ownership of the clone object, so it can delete it when it is not used anymore. This will leak otherwise.

        mzimmersM 1 Reply Last reply
        0
        • GrecKoG GrecKo

          But here the thing to do is let the QML engine have the ownership of the clone object, so it can delete it when it is not used anymore. This will leak otherwise.

          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #6

          @GrecKo said in can I make a temporary, local copy of a property?:

          But here the thing to do is let the QML engine have the ownership of the clone object

          So, in my example, who owns equipmentCopy? The creation stems from QML, but the actual creation occurs in C++, so I'm not sure how this gets sorted out.

          GrecKoG 1 Reply Last reply
          0
          • mzimmersM mzimmers

            @GrecKo said in can I make a temporary, local copy of a property?:

            But here the thing to do is let the QML engine have the ownership of the clone object

            So, in my example, who owns equipmentCopy? The creation stems from QML, but the actual creation occurs in C++, so I'm not sure how this gets sorted out.

            GrecKoG Online
            GrecKoG Online
            GrecKo
            Qt Champions 2018
            wrote on last edited by
            #7

            @mzimmers
            as stated here https://doc.qt.io/qt-6/qtqml-cppintegration-data.html#data-ownership if you return an object from a Q_INVOKABLE function without a QObject parent and an explicit call to QQmlEngine::setObjectOwnership, the QML engine will own it. That's what you want for the clone, not for the real one though.

            mzimmersM 1 Reply Last reply
            0
            • GrecKoG GrecKo

              @mzimmers
              as stated here https://doc.qt.io/qt-6/qtqml-cppintegration-data.html#data-ownership if you return an object from a Q_INVOKABLE function without a QObject parent and an explicit call to QQmlEngine::setObjectOwnership, the QML engine will own it. That's what you want for the clone, not for the real one though.

              mzimmersM Offline
              mzimmersM Offline
              mzimmers
              wrote on last edited by mzimmers
              #8

              @GrecKo if you please, I'd like to be really clear on this. Here's my Q_INVOKABLE function:

              Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
              {
                  auto equipment {std::make_shared<Equipment>(this)};
                  const auto i {getIndex(uuid)};
                  if (i != NgaUI::NOT_IN_LIST) {
                      equipment = m_list.at(i);
                  }
                  return equipment.get();
              }
              

              So, this object is indeed parented, correct? Are you saying that this is NOT what I want for my clone?

              EDIT: The function above is used in two places: directly in my QML, and also by this function:

              Equipment* EquipmentProxyModel::getEquipment(int proxyIndex)
              {
                  Equipment *equipment { nullptr };
                  const auto source {qobject_cast<EquipmentModel *>(sourceModel())};
                  if (source != nullptr)
                  {
                      auto sourceIndex {mapToSource(index(proxyIndex, 0))};
                      if (sourceIndex.isValid())
                      {
                          auto uuid {source->data(sourceIndex, EquipmentModel::EquipmentRoles::UuidRole).toUuid()};
                          equipment = source->getEquipment(uuid);
                      }
                  }
                  return equipment == nullptr ? new Equipment(this) : equipment;
              }
              

              This function too is called only from QML.

              GrecKoG 1 Reply Last reply
              0
              • mzimmersM mzimmers

                @GrecKo if you please, I'd like to be really clear on this. Here's my Q_INVOKABLE function:

                Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
                {
                    auto equipment {std::make_shared<Equipment>(this)};
                    const auto i {getIndex(uuid)};
                    if (i != NgaUI::NOT_IN_LIST) {
                        equipment = m_list.at(i);
                    }
                    return equipment.get();
                }
                

                So, this object is indeed parented, correct? Are you saying that this is NOT what I want for my clone?

                EDIT: The function above is used in two places: directly in my QML, and also by this function:

                Equipment* EquipmentProxyModel::getEquipment(int proxyIndex)
                {
                    Equipment *equipment { nullptr };
                    const auto source {qobject_cast<EquipmentModel *>(sourceModel())};
                    if (source != nullptr)
                    {
                        auto sourceIndex {mapToSource(index(proxyIndex, 0))};
                        if (sourceIndex.isValid())
                        {
                            auto uuid {source->data(sourceIndex, EquipmentModel::EquipmentRoles::UuidRole).toUuid()};
                            equipment = source->getEquipment(uuid);
                        }
                    }
                    return equipment == nullptr ? new Equipment(this) : equipment;
                }
                

                This function too is called only from QML.

                GrecKoG Online
                GrecKoG Online
                GrecKo
                Qt Champions 2018
                wrote on last edited by GrecKo
                #9

                @mzimmers I don't know if it is parented but I assume it is if the Equipment constructor pass this to the QObject constructor.
                I also don't know how the equipments in your list are constructed.

                Your getEquipment(const QUuid &uuid) is buggy.
                When the uuid is not found you return a default constructed Equipment that will get deleted since the shared_ptr will go out of scope.

                returning nullptr is fine, what's the point of return equipment == nullptr ? new Equipment(this) : equipment; ? what will you do with a default constructed Equipment?

                mzimmersM 1 Reply Last reply
                0
                • GrecKoG GrecKo

                  @mzimmers I don't know if it is parented but I assume it is if the Equipment constructor pass this to the QObject constructor.
                  I also don't know how the equipments in your list are constructed.

                  Your getEquipment(const QUuid &uuid) is buggy.
                  When the uuid is not found you return a default constructed Equipment that will get deleted since the shared_ptr will go out of scope.

                  returning nullptr is fine, what's the point of return equipment == nullptr ? new Equipment(this) : equipment; ? what will you do with a default constructed Equipment?

                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #10

                  @GrecKo this is my Equipment c'tor (nothing unusual):

                  Equipment::Equipment(QObject *parent) : QObject(parent) {}
                  

                  So, according to the doc you cited, am I correct that this will have C++ ownership?

                  @GrecKo said in can I make a temporary, local copy of a property?:

                  what will you do with a default constructed Equipment

                  I do this in my QML:

                  property Equipment equipment
                  property Equipment equipmentCopy: equipmentProxyModel !== null ? equipmentProxyModel.getEquipment(-1) : null
                  
                  Component.onCompleted: {
                      Fn.copyEquipment(equipmentCopy, equipment)
                  }
                  

                  So if I modify my function like this:

                  Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
                  {
                      auto equipment {std::make_shared<Equipment>(this)};
                      const auto i {getIndex(uuid)};
                      if (i != NgaUI::NOT_IN_LIST) {
                          equipment = m_list.at(i);
                          QJSEngine::setObjectOwnership(equipment.get(), QJSEngine::JavaScriptOwnership);
                      }
                      return equipment.get();
                  }
                  

                  Does this pass ownership of this Equipment object to the QML? This would seem to be the desired behavior.

                  GrecKoG 1 Reply Last reply
                  0
                  • mzimmersM mzimmers

                    @GrecKo this is my Equipment c'tor (nothing unusual):

                    Equipment::Equipment(QObject *parent) : QObject(parent) {}
                    

                    So, according to the doc you cited, am I correct that this will have C++ ownership?

                    @GrecKo said in can I make a temporary, local copy of a property?:

                    what will you do with a default constructed Equipment

                    I do this in my QML:

                    property Equipment equipment
                    property Equipment equipmentCopy: equipmentProxyModel !== null ? equipmentProxyModel.getEquipment(-1) : null
                    
                    Component.onCompleted: {
                        Fn.copyEquipment(equipmentCopy, equipment)
                    }
                    

                    So if I modify my function like this:

                    Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
                    {
                        auto equipment {std::make_shared<Equipment>(this)};
                        const auto i {getIndex(uuid)};
                        if (i != NgaUI::NOT_IN_LIST) {
                            equipment = m_list.at(i);
                            QJSEngine::setObjectOwnership(equipment.get(), QJSEngine::JavaScriptOwnership);
                        }
                        return equipment.get();
                    }
                    

                    Does this pass ownership of this Equipment object to the QML? This would seem to be the desired behavior.

                    GrecKoG Online
                    GrecKoG Online
                    GrecKo
                    Qt Champions 2018
                    wrote on last edited by GrecKo
                    #11

                    @mzimmers said in can I make a temporary, local copy of a property?:

                    So, according to the doc you cited, am I correct that this will have C++ ownership?

                    yes.

                    @mzimmers said in can I make a temporary, local copy of a property?:

                    So if I modify my function like this:

                    ?
                    QJSEngine::setObjectOwnership(equipment.get(), QJSEngine::JavaScriptOwnership);
                    You don't want to do that for an object you manage, you want to keep the ownership on the c++ side for an object on your list, only give it to QML for the cloned object.

                    What I would do if I were you (since the dangling pointer issue with your temporary shared_ptr is still present in your code):
                    No need to return a dummy object in getEquipment:

                    Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
                    {
                       const auto i {getIndex(uuid)};
                        if (i == NgaUI::NOT_IN_LIST) {
                            return nullptr;
                        }
                        return m_list.at(i).get();
                    }
                    

                    Or if for some obscure reason you don't like guard clauses and want multiple returns:

                    Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
                    {   
                       Equipment* equipment = nullptr;
                       const auto i {getIndex(uuid)};
                        if (i != NgaUI::NOT_IN_LIST) {
                            equipment = m_list.at(i).get();
                        }
                        return equipment.
                    }
                    

                    Have a cloneequipment function returning a new parent-less object (here or as member function in Equipment).

                    Equipment* Fn::cloneEquipment(Equipment* sourceEquipment) {
                       Equipment* clone = new Equipment();
                       // copy from source to clone
                       return clone; 
                    }
                    

                    And use it like so in QML:

                    property Equipment equipment
                    property Equipment equipmentCopy: Fn.cloneEquipment(equipment)
                    
                    mzimmersM 1 Reply Last reply
                    1
                    • GrecKoG GrecKo

                      @mzimmers said in can I make a temporary, local copy of a property?:

                      So, according to the doc you cited, am I correct that this will have C++ ownership?

                      yes.

                      @mzimmers said in can I make a temporary, local copy of a property?:

                      So if I modify my function like this:

                      ?
                      QJSEngine::setObjectOwnership(equipment.get(), QJSEngine::JavaScriptOwnership);
                      You don't want to do that for an object you manage, you want to keep the ownership on the c++ side for an object on your list, only give it to QML for the cloned object.

                      What I would do if I were you (since the dangling pointer issue with your temporary shared_ptr is still present in your code):
                      No need to return a dummy object in getEquipment:

                      Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
                      {
                         const auto i {getIndex(uuid)};
                          if (i == NgaUI::NOT_IN_LIST) {
                              return nullptr;
                          }
                          return m_list.at(i).get();
                      }
                      

                      Or if for some obscure reason you don't like guard clauses and want multiple returns:

                      Equipment *EquipmentModel::getEquipment(const QUuid &uuid)
                      {   
                         Equipment* equipment = nullptr;
                         const auto i {getIndex(uuid)};
                          if (i != NgaUI::NOT_IN_LIST) {
                              equipment = m_list.at(i).get();
                          }
                          return equipment.
                      }
                      

                      Have a cloneequipment function returning a new parent-less object (here or as member function in Equipment).

                      Equipment* Fn::cloneEquipment(Equipment* sourceEquipment) {
                         Equipment* clone = new Equipment();
                         // copy from source to clone
                         return clone; 
                      }
                      

                      And use it like so in QML:

                      property Equipment equipment
                      property Equipment equipmentCopy: Fn.cloneEquipment(equipment)
                      
                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #12

                      @GrecKo said in can I make a temporary, local copy of a property?:

                      You don't want to do that for an object you manage, you want to keep the ownership on the c++ side for an object on your list

                      I should have mentioned that the functions getEquipment(), both in the model and the proxy model, are used only for making a (temporary) clone copy. This object never enters the list; it only serves as a template for creating a HTTP PATCH request. When I receive a reply to this request, I update the correct element in the model list.

                      1 Reply Last reply
                      0
                      • mzimmersM mzimmers has marked this topic as solved on
                      • mzimmersM mzimmers referenced this topic on

                      • Login

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