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. Passing QObjectList from C++ to QML and back
Forum Updated to NodeBB v4.3 + New Features

Passing QObjectList from C++ to QML and back

Scheduled Pinned Locked Moved Solved QML and Qt Quick
8 Posts 2 Posters 1.1k 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.
  • S Offline
    S Offline
    SKovalev
    wrote on last edited by
    #1

    Hello.

    I try to pass QList<QObject*> from C++ to QML, reorder it in GridLayout and pass it back.

    I have done first two steps here. But I can't deal with last step.

    I have tried to pass model back to C++ like this:

    Button {
        onClicked: gridEx.receiveData(grid.inputModel)
    }
    

    Then I have checked the QList after reordering in GridLayout but it is not changed.

    So I will be grateful for any suggestion.

    1 Reply Last reply
    0
    • dheerendraD Offline
      dheerendraD Offline
      dheerendra
      Qt Champions 2022
      wrote on last edited by
      #2

      When you reorder how are changing ordering in qlist back in c++ ?

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

      1 Reply Last reply
      0
      • S Offline
        S Offline
        SKovalev
        wrote on last edited by
        #3

        @dheerendra, sorry but I don't understand the question.

        1 Reply Last reply
        0
        • dheerendraD Offline
          dheerendraD Offline
          dheerendra
          Qt Champions 2022
          wrote on last edited by
          #4

          You said that you are reordering the elements. This is done at Qml side. How are you updating back at c++ side ?

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

          1 Reply Last reply
          0
          • S Offline
            S Offline
            SKovalev
            wrote on last edited by SKovalev
            #5

            This is the question. I can't to deal with this.

            I pass the list like this:

            QList<QObject*> dataList;
            dataList.append(new Block("俄", QColor("purple")));
            ..
            engine.rootContext()->setContextProperty("inputModel", QVariant::fromValue(dataList));.
            

            Then I use it in QML like this:

            GridViewFluid {
                dataModel: inputModel
            }
            

            Then I can manipulate (reorder all elements in GridView. But as far as I know Qt the data model is separated from view. Thus while reordering I don't change the model. Just the view. I have checked this in C++ side by printing the list after reordering like this:

            // main.qml
            Button {
                onClicked: receiver.receiveData()
            }
            
            // gridviewextension.cpp
            extern QList<QObject*> dataList;
            void GridViewExtension::receiveData()
            {
            ...
            }
            
            1 Reply Last reply
            0
            • dheerendraD Offline
              dheerendraD Offline
              dheerendra
              Qt Champions 2022
              wrote on last edited by
              #6

              When you use QVariant::fromvalue it returns the copy of the original value. So if you do anything in view it will not change in c++ side. Simply put u can't achieve this in current scenario. If the model is exposed as in mv framework then we can do something.

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

              S 1 Reply Last reply
              1
              • dheerendraD dheerendra

                When you use QVariant::fromvalue it returns the copy of the original value. So if you do anything in view it will not change in c++ side. Simply put u can't achieve this in current scenario. If the model is exposed as in mv framework then we can do something.

                S Offline
                S Offline
                SKovalev
                wrote on last edited by SKovalev
                #7

                @dheerendra said in Passing QObjectList from C++ to QML and back:

                When you use QVariant::fromvalue it returns the copy of the original value.

                Thank You! I didn't know this. I should read the documentation more careful.

                If the model is exposed as in mv framework then we can do something.

                How to achieve this? I have tried to pass model from QML to C++ without success like this:

                // main.qml
                Button {
                    onClicked: receiver.receiveData(grid.dataModel)
                }
                
                // gridviewextension.cpp
                void GridViewExtension::receiveData(QList<QObject*> dataList)
                {
                ...
                }
                
                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SKovalev
                  wrote on last edited by
                  #8

                  Finally I have coped with this task.

                  First of all I have created custom model like this:

                  class Block
                  {
                  public:
                      Block(QString data = QString(), QColor color = QColor())
                          : m_data(data)
                          , m_color(color)
                      {}
                  
                      QString data() const { return m_data; }
                  
                      QColor color() const { return m_color; }
                  
                  private:
                      QString m_data;
                      QColor m_color;
                  };
                  
                  
                  class BlockModel : public QAbstractListModel
                  {
                      Q_OBJECT
                  
                  public:
                      enum BlockRoles {
                          DataRole = Qt::UserRole + 1,
                          ColorRole
                      };
                  
                      BlockModel(QObject *parent = nullptr) : QAbstractListModel (parent) {}
                  
                      void addBlock(const Block &block)
                      {
                          beginInsertRows(QModelIndex(), rowCount(), rowCount());
                          m_blocks << block;
                          endInsertRows();
                      }
                  
                      int rowCount(const QModelIndex &parent = QModelIndex()) const
                      {
                          Q_UNUSED(parent);
                          return m_blocks.count();
                      }
                  
                      QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
                      {
                          if (index.row() < 0 || index.row() >= m_blocks.count())
                              return QVariant();
                  
                          const Block &block = m_blocks[index.row()];
                          if (DataRole == role)
                              return block.data();
                          else if (ColorRole == role)
                              return block.color();
                  
                          return QVariant();
                      }
                  
                      Q_INVOKABLE void move(int from, int to)
                      {
                          if (from == to || from < 0 || from >= m_blocks.count() || to < 0 || to >= m_blocks.count())
                              return;
                  
                          /*
                           * Read carefully:
                           * - https://doc.qt.io/qt-5/qabstractitemmodel.html#beginMoveRows
                           * - https://bugreports.qt.io/browse/QTBUG-6940
                           */
                          int destinationChild = to;
                          if (destinationChild - from == 1)
                              ++destinationChild;
                  
                          beginMoveRows(QModelIndex(), from, from, QModelIndex(), destinationChild);
                          auto b = m_blocks.takeAt(from);
                          m_blocks.insert(to, b);
                          endMoveRows();
                      }
                  
                  protected:
                      QHash<int, QByteArray> roleNames() const
                      {
                          QHash<int, QByteArray> roles;
                          roles[DataRole] = "data";
                          roles[ColorRole] = "color";
                          return roles;
                      }
                  
                  private:
                      QVector<Block> m_blocks;
                  };
                  

                  Then I have passe it without QVariant (many thanks to @dheerendra) like this:

                     BlockModel dataList;
                      dataList.addBlock(Block("1", QColor("purple")));
                      dataList.addBlock(Block("2", QColor("cyan")));
                      dataList.addBlock(Block("3", QColor("magenta")));
                      dataList.addBlock(Block("4", QColor("chartreuse")));
                  
                      QQmlApplicationEngine engine;
                      engine.rootContext()->setContextProperty("inputModel", &dataList);
                  

                  And last I have used it in my GridView like this:

                  GridView {
                      property var dataModel: ListModel{}
                  
                      onDataModelChanged: visualModel.model = dataModel
                  
                      id: root
                  
                      height: parent.height - 10
                      width: parent.width - 10
                      x: 5
                      y: 5
                  
                      cellHeight: getSize()
                      cellWidth: cellHeight
                  
                      displaced: Transition {
                          NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
                      }
                  
                      model: DelegateModel {
                          id: visualModel
                  
                          model: parent.dataModel
                  
                          delegate: MouseArea {
                              property int visualIndex: DelegateModel.itemsIndex
                  
                              id: delegateRoot
                  
                              height: root.cellHeight
                              width: root.cellWidth
                  
                              drag.target: block
                  
                              Rectangle {
                                  id: block
                  
                                  objectName: "Block"
                  
                                  anchors {
                                      horizontalCenter: parent.horizontalCenter
                                      verticalCenter: parent.verticalCenter
                                  }
                  
                                  height: root.cellHeight - 8
                                  width: root.cellWidth - 8
                                  radius: width / 10
                  
                                  color: model.color
                                  Text {
                                      anchors.fill: parent
                  
                                      fontSizeMode: Text.Fit
                                      minimumPointSize: 8
                                      font.pointSize: 1000
                  
                                      text: model.data
                  
                                      horizontalAlignment: Text.AlignHCenter
                                      verticalAlignment: Text.AlignVCenter
                  
                                      color: "white"
                                  }
                  
                                  Drag.active: delegateRoot.drag.active
                                  Drag.source: delegateRoot
                                  Drag.hotSpot.x: width / 2
                                  Drag.hotSpot.y: width / 2
                  
                                  states: [
                                      State {
                                          when: block.Drag.active
                                          ParentChange {
                                              target: block
                                              parent: root
                                          }
                  
                                          AnchorChanges {
                                              target: block;
                                              anchors.horizontalCenter: undefined
                                              anchors.verticalCenter: undefined
                                          }
                                      }
                  
                                  ]
                              }
                  
                              DropArea {
                                  anchors { fill: parent; margins: 15 }
                  
                                  onEntered: dataModel.move(drag.source.visualIndex, delegateRoot.visualIndex)
                              }
                          }
                      }
                  
                      function getSize() {
                          var minSize = 25
                  
                          if (model.count <= 0 || height <= 0 || width <= 0)
                              return minSize
                  
                          var size = minSize
                          var p = 0
                  
                          for (var rows = 1, columns = model.count;
                               rows <= model.count;
                               ++rows, columns = 1 + (model.count - 1) / rows)
                          {
                              var s = Math.min(height / rows, width / columns)
                  
                              if (s > size)
                                  size = s
                  
                              if (s < p)
                                  return size
                              else
                                  p = s
                          }
                  
                          return size
                      }
                  }
                  
                  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