Passing C++ Data Structure to QML
-
Hello,
I am trying to implement Custom Table View in qml to pass to QQucikWidget, I have implemented Custom Model that inherits from QAbstractTableModel, my problem is I do want to pass a whole structure as one column but I couldn't manage to implement the QML part of that. Here is my data that I am using in model#include <array> #include <QObject> struct Item { unsigned int id1; unsigned int id2; bool flag; }; struct TData { unsigned int id1; unsigned int id2; std::array<Item, 4> items; }; Q_DECLARE_METATYPE(Item)
Here is my CustomModel implementations
// CustomTable.h enum Roles { ItemRole = Qt::UserRole + 1 }; // CustomTable.cpp QVariant CustomTable::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if(role == Qt::DisplayRole) { switch (index.column()) { case 0: return datas[index.row()].id1; case 1: return datas[index.row()].id2; } } else if(role == Roles::ItemRole) { qDebug() << "item role data called!"; switch (index.column()) { case 2: return QVariant::fromValue(datas[index.row()].items); } } // FIXME: Implement me! return QVariant(); } QHash<int, QByteArray> CustomTable::roleNames() const { QHash<int, QByteArray> roles; roles.insert(Qt::DisplayRole, "display"); roles.insert(Roles::ItemRole, "item"); return roles; }
Here is my QML file
// CustomTableView.qml import QtQuick 2.12 import QtQuick.Window 2.12 import Qt.labs.qmlmodels 1.0 import QtQuick.Controls 2.15 import CustomTable 1.0 Item { anchors.fill: parent HorizontalHeaderView { syncView: tableView id: horizontalHeader anchors.left: tableView.left } TableView { id: tableView anchors.top: horizontalHeader.bottom anchors.fill: parent clip: true model: CustomTable { id: customTable } rowSpacing: 5 onWidthChanged: forceLayout() onHeightChanged: forceLayout() columnWidthProvider: function(){return tableView.width / tableView.model.columnCount();} rowHeightProvider: function(){return tableView.height / 10;} topMargin: horizontalHeader.implicitHeight delegate: DelegateChooser { DelegateChoice { column: 0 delegate: Text { id: id1Text text: display horizontalAlignment: Text.AlignHCenter // Center text horizontally } } DelegateChoice { column: 1 delegate: Text { id: id3 text: display horizontalAlignment: Text.AlignHCenter // Center text horizontally } } DelegateChoice { column: 2 delegate: Item { property var itemData: item Row { spacing: 10 width: { // Get the column width from the TableView model var columnWidth = tableView.columnWidthProvider(tableView.model, 2); // Subtract the spacing to account for spacing between rectangles return columnWidth - spacing; } Rectangle { id: item1 width: parent.width / 5 // Set the width to a fraction of the parent's width height: parent.height color: "red" Text { id: item1Text text: item[0].id1 anchors.centerIn: parent } } Rectangle { id: item2 width: parent.width / 5 // Set the width to a fraction of the parent's width height: 30 color: "blue" Text { id: item2Text text: item[1].id1 anchors.centerIn: parent } } Rectangle { id: item3 width: parent.width / 5 // Set the width to a fraction of the parent's width height: 30 color: "green" Text { id: item3Text text: item[2].id1 anchors.centerIn: parent } } Rectangle { id: item4 width: parent.width / 5 // Set the width to a fraction of the parent's width height: 30 color: "yellow" Text { id: item4Text text: item[3].id1 anchors.centerIn: parent } } } } } } } }
As you can see I am trying to get the items in TData in column 2 but I couldn't manage to parse it through, I do get the "TypeError: Cannot read property 'id1' of undefined" error, What should I do, I kinda donot want to make 3 roles for each item and I want to see all 4 of them in 1 column. Is there a way for that? For the second part , since I'm new to QML, any improvements to the code will be very helpful.
-
Hello,
I am trying to implement Custom Table View in qml to pass to QQucikWidget, I have implemented Custom Model that inherits from QAbstractTableModel, my problem is I do want to pass a whole structure as one column but I couldn't manage to implement the QML part of that. Here is my data that I am using in model#include <array> #include <QObject> struct Item { unsigned int id1; unsigned int id2; bool flag; }; struct TData { unsigned int id1; unsigned int id2; std::array<Item, 4> items; }; Q_DECLARE_METATYPE(Item)
Here is my CustomModel implementations
// CustomTable.h enum Roles { ItemRole = Qt::UserRole + 1 }; // CustomTable.cpp QVariant CustomTable::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if(role == Qt::DisplayRole) { switch (index.column()) { case 0: return datas[index.row()].id1; case 1: return datas[index.row()].id2; } } else if(role == Roles::ItemRole) { qDebug() << "item role data called!"; switch (index.column()) { case 2: return QVariant::fromValue(datas[index.row()].items); } } // FIXME: Implement me! return QVariant(); } QHash<int, QByteArray> CustomTable::roleNames() const { QHash<int, QByteArray> roles; roles.insert(Qt::DisplayRole, "display"); roles.insert(Roles::ItemRole, "item"); return roles; }
Here is my QML file
// CustomTableView.qml import QtQuick 2.12 import QtQuick.Window 2.12 import Qt.labs.qmlmodels 1.0 import QtQuick.Controls 2.15 import CustomTable 1.0 Item { anchors.fill: parent HorizontalHeaderView { syncView: tableView id: horizontalHeader anchors.left: tableView.left } TableView { id: tableView anchors.top: horizontalHeader.bottom anchors.fill: parent clip: true model: CustomTable { id: customTable } rowSpacing: 5 onWidthChanged: forceLayout() onHeightChanged: forceLayout() columnWidthProvider: function(){return tableView.width / tableView.model.columnCount();} rowHeightProvider: function(){return tableView.height / 10;} topMargin: horizontalHeader.implicitHeight delegate: DelegateChooser { DelegateChoice { column: 0 delegate: Text { id: id1Text text: display horizontalAlignment: Text.AlignHCenter // Center text horizontally } } DelegateChoice { column: 1 delegate: Text { id: id3 text: display horizontalAlignment: Text.AlignHCenter // Center text horizontally } } DelegateChoice { column: 2 delegate: Item { property var itemData: item Row { spacing: 10 width: { // Get the column width from the TableView model var columnWidth = tableView.columnWidthProvider(tableView.model, 2); // Subtract the spacing to account for spacing between rectangles return columnWidth - spacing; } Rectangle { id: item1 width: parent.width / 5 // Set the width to a fraction of the parent's width height: parent.height color: "red" Text { id: item1Text text: item[0].id1 anchors.centerIn: parent } } Rectangle { id: item2 width: parent.width / 5 // Set the width to a fraction of the parent's width height: 30 color: "blue" Text { id: item2Text text: item[1].id1 anchors.centerIn: parent } } Rectangle { id: item3 width: parent.width / 5 // Set the width to a fraction of the parent's width height: 30 color: "green" Text { id: item3Text text: item[2].id1 anchors.centerIn: parent } } Rectangle { id: item4 width: parent.width / 5 // Set the width to a fraction of the parent's width height: 30 color: "yellow" Text { id: item4Text text: item[3].id1 anchors.centerIn: parent } } } } } } } }
As you can see I am trying to get the items in TData in column 2 but I couldn't manage to parse it through, I do get the "TypeError: Cannot read property 'id1' of undefined" error, What should I do, I kinda donot want to make 3 roles for each item and I want to see all 4 of them in 1 column. Is there a way for that? For the second part , since I'm new to QML, any improvements to the code will be very helpful.
-