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 populate a TableView's rows with a C++ QVariantList?
Forum Update on Monday, May 27th 2025

Can I populate a TableView's rows with a C++ QVariantList?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
4 Posts 2 Posters 734 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.
  • K Offline
    K Offline
    KidTrent
    wrote on last edited by KidTrent
    #1

    I'm trying to make a recyclable TableView where each cell in a column can be editable based on the value (like a C# DataGridView).
    I've started this off by trying to populate the table's rows using a QVariantList that is retrieved from a C++ class. However, I get a few error...

    Is there anyway to accomplish this without having to define a QAbstractTableModel in C++? My hopes was that I could just define the columns via QML like shown in my code.

    Errors
    qrc:/AppTableView.qml:10:12: QML TableModel: expected row for role "display" of TableModelColumn at index 0 to be a simple object, but it's QObject* instead: QVariant(QObject*, TableValue(0x20fa91742c0))
    qrc:/AppTableView.qml:10:12: QML TableModel: expected row for role "display" of TableModelColumn at index 1 to be a simple object, but it's QObject* instead: QVariant(QObject*, TableValue(0x20fa91742c0))
    qrc:/AppTableView.qml:0: ReferenceError: display is not defined
    qrc:/AppTableView.qml:0: ReferenceError: display is not defined
    qrc:/AppTableView.qml:0: ReferenceError: display is not defined
    qrc:/AppTableView.qml:32: ReferenceError: display is not defined
    qrc:/AppTableView.qml:32: ReferenceError: display is not defined
    qrc:/AppTableView.qml:32: ReferenceError: display is not defined

    My Code

    AppTableView.qml

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    import Qt.labs.qmlmodels 1.0
    
    TableView {
        id: root
        width: parent.width
        height: parent.height
    
        model: TableModel {
            TableModelColumn { display: "id" }
            TableModelColumn { display: "title" }
    
            // This does not work...
            rows: sampleController.tableValues
    
            /// This works, but is not populated by an existing collection of data...
            /*rows: [
                {
                    id: 0,
                    title: "Title0"
                },
                {
                    id: 1,
                    title: "Title1"
                }
            ]*/
        }
    
        delegate: TextArea {
            id: textField
            text: display
        }
    }
    

    main.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.12
    
    Window {
        width: 640
        height: 480
        visible: true
        title: qsTr("Hello World")
    
        AppTableView {
    
        }
    }
    

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    #include "SampleController.h"
    
    int main(int argc, char *argv[])
    {
    #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif
    
        QGuiApplication app(argc, argv);
    
    
        SampleController sampleController;
    
        QQmlApplicationEngine engine;
        engine.rootContext()->setContextProperty("sampleController", &sampleController);
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    

    SampleController.h

    #ifndef SAMPLECONTROLLER_H
    #define SAMPLECONTROLLER_H
    
    #include <QObject>
    #include <QVariantList>
    
    #include "SampleThread.h"
    
    class TableValue : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY(int id MEMBER m_id);
        Q_PROPERTY(QString title MEMBER m_title);
    
    public:
        explicit TableValue(
                const int id,
                const QString& title,
                QObject *parent = nullptr) :
            QObject(parent),
            m_id(id),
            m_title(title)
        {
    
        }
    
    private:
        int m_id;
        QString m_title;
    };
    
    class SampleController : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY(QVariantList tableValues READ tableValues NOTIFY tableValuesChanged);
    
    public:
        explicit SampleController(
                QObject *parent = nullptr);
    
        const QVariantList tableValues() const;
    
    signals:
    
        void tableValuesChanged(
                const QVariantList& tableValues);
    
    private:
        QList<TableValue*> m_table_values;
    };
    
    
    #endif // SAMPLECONTROLLER_H
    

    SampleController.cpp

    #include <QDebug>
    
    #include "SampleController.h"
    
    SampleController::SampleController(
            QObject *parent) :
        QObject(parent)
    {
        m_table_values.append(new TableValue(0, "Title0", this));
        m_table_values.append(new TableValue(1, "Title1", this));
        m_table_values.append(new TableValue(2, "Title2", this));
    }
    
    const QVariantList SampleController::tableValues() const
    {
        QVariantList list;
    
        for(int i = 0; i < m_table_values.size(); i++)
        {
            list.append(QVariant::fromValue(m_table_values[i]));
        }
    
        return list;
    }
    
    1 Reply Last reply
    0
    • K Offline
      K Offline
      KidTrent
      wrote on last edited by KidTrent
      #2

      So I did some research and I didn't find any direct answer to my question... but with a little playing around I was able to produce what I wanted by changing AppTableView.qml a little.

      Specifically, the TableModelColumn's now get the display via a function... I just don't understand why it doesn't work by directly providing the property name we are looking for (shown in my original post)... or even by doing return rows[modelIndex.row].id...

      TableModelColumn {
          display: function(modelIndex) {
              return sampleController.tableValues[modelIndex.row].id
          }
      }
      

      AppTableView.qml

      TableView {
          id: root
          width: parent.width
          height: parent.height
      
          model: TableModel {
              TableModelColumn {
                  display: function(modelIndex) {
                      return sampleController.tableValues[modelIndex.row].id
                  }
              }
              TableModelColumn {
                  display: function(modelIndex) {
                      return sampleController.tableValues[modelIndex.row].title
                  }
              }
      
              // This does not work...
              rows: sampleController.tableValues
      
              // This works, but is not populated by an existing collection of data...
              /*rows: [
                  {
                      id: 0,
                      title: "Title0"
                  },
                  {
                      id: 1,
                      title: "Title1"
                  }
              ]*/
          }
      
          delegate: TextArea {
              id: textField
              text: display
          }
      }
      
      1 Reply Last reply
      0
      • K Offline
        K Offline
        KidTrent
        wrote on last edited by
        #3

        Anyone running into the same issue, aside from my solution above I could not find any other working solutions. That being said, even my solution above has issues...

        For example, if I were to add a "Add Row" button that inserts a TableValue object into m_table_values. This addition is not reflected to the model view (and according to the documentation this isn't supported). However, if you are okay with just editing existing entries... this method works great (they update).

        That being said, I ended up just making a basic QAbstractTableModel class and then made several others that inherit from my BasicTableModel... This produced what I wanted, but it's just very disappointing that this can't be accomplished via QML directly...

        1 Reply Last reply
        0
        • J Offline
          J Offline
          jars121
          wrote on last edited by
          #4

          Thanks for providing the update.

          I'm looking to do something similar at the moment, and am somewhat perplexed by the QAbstractItemModel approach. It seems overly complex for managing some basic data types in a QML TableView, and (from the initial research I've conducted) it seems that the 'roles' have to be pre-defined, which surely makes the use of a generic QAbstractItemModel-based class (i.e. one where the class can be instantiated for multiple QML TableViews within the one application, each with its own set of columns, etc.) either very complicated or not possible?

          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