QML TableView with dynamic number of columns - c++

I have been trying to use a QML TableView to display a QAbstractTableModel. The missing part of the equation seems to be that it is not possible to have a variable number of columns in the TableView, despite overriding QAbstractItemModel::roleNames which should tell Qt the number and name of my columns. I tried testing this out using only QML:
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
anchors.fill: parent
property real showImage: 1.0
width: 500
TableView {
id: myTable
model: myModel
// TableViewColumn {
// role: "title"; title: "Name"; width: 200
// }
}
ListModel {
id: myModel
ListElement {
title: "item one"
}
ListElement {
title: "item two"
}
}
}
When run this doesn't show anything despite the TableView's mode containing ListElements with roles defined in them.
However if the above code is uncommented and a TableViewColumn is defined then the column will display data for that role as expected but the table will still not display any other roles. Obviously that will only work for a statically defined number of columns and not my case where the number of columns is not known until run time.
The example given is basically the same as my real life example except that my model is defined in C++.
It seems as if this may have already been asked here but it did not gain any response.
EDIT: I had tried calling a javascript function:
function addColumnToTable(roleName) {
var columnString = 'import QtQuick 2.3; import QtQuick.Controls 1.2; TableViewColumn {role: "'
+ roleName + '"; title: "' + roleName + '"; width: 40}';
var column = Qt.createQmlObject(
columnString
, myTable
, "dynamicSnippet1")
myTable.addColumn(column);
}
From C++:
QVariant roleName = "name";
QObject *root = view->rootObject();
QMetaObject::invokeMethod(root, "addColumnToTable", Q_ARG(QVariant, roleName));
This at least allowed me to dynamically add columns from C++ although not from within the model/view architecture. Yoann's solution is far and away better than this though.

You could create dynamically as many TableViewColumn as you need, using the resources property of your TableView.
You will have to add a method in your custom model class which will give you the roleNames you want to display.
QML:
Component
{
id: columnComponent
TableViewColumn{width: 100 }
}
TableView {
id: view
anchors.fill: parent
resources:
{
var roleList = myModel.customRoleNames
var temp = []
for(var i=0; i<roleList.length; i++)
{
var role = roleList[i]
temp.push(columnComponent.createObject(view, { "role": role, "title": role}))
}
return temp
}
model: myModel
MyModel.h:
class MyModel: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QStringList userRoleNames READ userRoleNames CONSTANT)
public:
explicit MyModel(QObject *parent = 0);
enum MyModelRoles {
UserRole1 = Qt::UserRole + 1,
UserRole2,
...
};
QStringList userRoleNames();
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
...
private:
QHash<int, QByteArray> roleNames() const;
...
};
MyModel.cpp:
...
...
QHash<int, QByteArray> MyModel::roleNames() const {
QHash<int, QByteArray> roles = QAbstractListModel::roleNames ();
roles[UserRole1] = "whatever";
roles[UserRole2] = "youwant";
return roles;
}
QStringList MyModel::userRoleNames() // Return ordered List of user-defined roles
{
QMap<int, QString> res;
QHashIterator<int, QByteArray> i(roleNames());
while (i.hasNext()) {
i.next();
if(i.key() > Qt::UserRole)
res[i.key()] = i.value();
}
return res.values();
}
...
...

The solution with resources does not work for me (Qt 5.6). The TableView is not updated.
This works for me:
Component{
id: columnComponent
TableViewColumn{width: 30 }
}
TableView {
id: tableView
model: listModel
property var titles: somethingDynamic
property var curTitles: {
var t=[]
for(var i=0;i<columnCount;i++){
t.push(getColumn(i).title)
}
return t
}
onTitlesChanged:{
for(var i=0;i<titles.length;i++){
if(curTitles.indexOf(titles[i])==-1){
var column = addColumn(columnComponent)
column.title=titles[i]
column.role=titles[i]
}
}
for(var i=curTitles.length-1;i>=0;i--){
if(titles.indexOf(curTitles[i])==-1){
removeColumn(i)
}
}
}
}
}
It also correctly updates drag-drop-reordered columns.

Another way to do it with an Instantiator:
TableView{
id: view
model: tableViewModel
Instantiator{
model: someStringList
onObjectAdded: view.addColumn(object)
onObjectRemoved: view.removeColumn(object)
delegate: TableViewColumn{
width: 100
title: modelData
role: modelData
}
}
}
This code (and the one from #palfi) cause some warning in the console:
For each column created there is:
qml: TableView::insertColumn(): you cannot add a column to multiple views
And then when column are removed it produce this warning:
file:///usr/lib/qt/qml/QtQuick/Controls/Private/BasicTableView.qml:297: Error: Invalid attempt to destroy() an indestructible object
If someone has a better solution, please post it!

Related

QSqlQueryModel - override function data not being called

I am trying to populate a TableView in QML with some information retrieved from a MySQL database.
I am able to connect to the database using QSqlQuery, but when trying to use QSqlQueryModel, it is not working (results obtained in the image at the end). I've been debugging the application, but the overrided function data and the overrided function roleNames of the model are never called.
This is how my model file looks like: tableModel.h
#ifndef TABLEMODEL_H
#define TABLEMODEL_H
#include <QObject>
#include <QtQml/qqml.h>
#include <QSqlQueryModel>
#include <source/database/mySQL/mySqlQueries.h>
class TableModel : public QSqlQueryModel {
Q_OBJECT
public:
// List all the roles that will be used in the TableView
enum Roles {
CHROM_ROLE = Qt::UserRole + 1,
POS_ROLE,
ID_ROLE,
REF_ROLE,
ALT_ROLE,
QUAL_ROLE
};
explicit TableModel(QObject *parent = 0);
// Override the method that will return the data
QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const override;
protected:
/* hashed table of roles for speakers.
* The method used in the wilds of the base class QAbstractItemModel,
* from which inherits the class QSqlQueryModel
* */
QHash<int, QByteArray> roleNames() const override;
};
#endif // TABLEMODEL_H
Here, the implementation of the file: tableModel.cpp
#include "tableModel.h"
TableModel::TableModel(QObject *parent) : QSqlQueryModel(parent) {
}
// The method for obtaining data from the model
QVariant TableModel::data( const QModelIndex & index, int role) const {
switch (role) {
case CHROM_ROLE:
return QString("%1, %2").arg(index.column()).arg(index.row());
case POS_ROLE:
return QString("%1, %2").arg(index.column()).arg(index.row());
case ID_ROLE:
return QString("%1, %2").arg(index.column()).arg(index.row());
case REF_ROLE:
return QString("%1, %2").arg(index.column()).arg(index.row());
case ALT_ROLE:
return QString("%1, %2").arg(index.column()).arg(index.row());
case QUAL_ROLE:
return QString("%1, %2").arg(index.column()).arg(index.row());
default:
break;
}
return QVariant();
}
QHash<int, QByteArray> TableModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[CHROM_ROLE] = "CHROM_ROLE";
roles[POS_ROLE] = "POS_ROLE";
roles[ID_ROLE] = "ID_ROLE";
roles[REF_ROLE] = "REF_ROLE";
roles[ALT_ROLE] = "ALT_ROLE";
roles[QUAL_ROLE] = "QUAL_ROLE";
return roles;
}
As you can see, I've overrided data and roleNames. None of those functions are called when executing it. (Right now, data should return the row and column numbers, not the real data).
The corresponding part of the qml file containing the TableView object is the following:
import QtQuick.Controls 2.4
import QtQuick.Controls 1.4 as Controls
import QtQuick.Window 2.11
import Qt.labs.qmlmodels 1.0
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("Title")
Controls.TableView {
id: tableview
width: root.width * 0.8
height: root.height * 0.8
anchors.centerIn: parent
clip: true
Controls.TableViewColumn {
role: "CHROM_ROLE" // These roles are roles names coincide with a C ++ model
title: "#Chrom"
}
Controls.TableViewColumn {
role: "POS_ROLE" // These roles are roles names coincide with a C ++ model
title: "Pos."
}
Controls.TableViewColumn {
role: "ID_ROLE" // These roles are roles names coincide with a C ++ model
title: "ID"
}
Controls.TableViewColumn {
role: "REF_ROLE" // These roles are roles names coincide with a C ++ model
title: "Ref."
}
Controls.TableViewColumn {
role: "ALT_ROLE" // These roles are roles names coincide with a C ++ model
title: "Alt."
}
Controls.TableViewColumn {
role: "QUAL_ROLE" // These roles are roles names coincide with a C ++ model
title: "Qual."
}
// We set the model in the TableView
model: TableModel
}
}
As you can see, the roles for each of the TableViewColumns, corresponds with the roles in the cpp file.
The pro file contains the following line (besides, SQL queries are working):
QT += sql
In the main.cpp file, I am instantiating everything like this.:
QGuiApplication app(argc, argv);
qmlRegisterType<TableModel>("TableModel", 1, 0, "TableModel");
TableModel tableModel;
MySqlConnector db;
db.connectToDB("localhost", "dbname", "user", "Password");
db.open();
// I've tested that the query is working using just QSqlQuery and retrieves info from database
tableModel.setQuery(MySQLQueries::queryBodyOfVCF.arg(1), db.db);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("TableModel", &tableModel);
const QUrl url(QStringLiteral("qrc:/views/MasterView.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();
When I execute it, this is what I am getting:
The expected results should be something like this (In the real database there is only one row, and as mentioned in the comments, tableModel.rowCount() returns 1 as expected). This is an example of real data that should be displayed:
chrom pos ref alt qual id
ctg1 9 A C, G 100 rs001
ctg3 12 C T 100 rs002
Is there something wrong with my implementation? I think that I may be me misunderstanding some concept, or something missing in the .h file or the .cpp file.
The problem is caused because you are using the name of the item: TableModel, the solution is to change the name of the context-property:
engine.rootContext()->setContextProperty("tableModel", &tableModel);
model: tableModel
On the other hand, I recommend using the model that is implemented in another post where I generalize the logic.

QAbstractTableModel::header data and QML TableView

I have subclasses the QAbstractTableModel and provided the headerData override:
/**
* #brief Obtains the header (columns) names.
* #param section: column number.
* #param orientation: Accepts only horizontal.
* #param role: Accepts only display.
* #return The column header text in case all params are valid.
* Otherwise empty QVariant.
*/
QVariant CVarTableModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation != Qt::Horizontal)
return QVariant();
if (section >= static_cast<int>(Columns::ZCOUNT))
return QVariant();
return QVariant::fromValue(static_cast<Columns>(section));
}
I am trying to figure out how to make my QML TableView component utilize this function. Is there a way to do this automatically?
Make your method invokbale from QML by using the macro Q_INVOKABLE. Then, use it in your QML as any other method:
class Model: public QStandardItemModel
{
public:
Model(QObject* parent=nullptr): QStandardItemModel(parent)
{
setColumnCount(2);
setRowCount(2);
}
Q_INVOKABLE virtual QVariant headerData(int section,
Qt::Orientation orientation,
int role=Qt::DisplayRole) const override
{
qDebug() << section << orientation << role;
if (role != Qt::DisplayRole)
return QVariant();
if (section == 0)
return "First Column";
return "Not first column";
}
};
// In main.cpp
Model* model = new Model();
QQuickView *view = new QQuickView;
view->rootContext()->setContextProperty("myModel", model);
view->setSource(QUrl("qrc:/main.qml"));
view->show();
TableView {
TableViewColumn {
role: "title"
title: myModel.headerData(0, Qt.Vertical);
width: 100
}
TableViewColumn {
role: "author"
title: myModel.headerData(1, Qt.Vertical);
width: 200
}
model: myModel
}
I found today a different solution to this I did not know: https://doc.qt.io/qt-6/qml-qtquick-controls2-horizontalheaderview.html
Column{
HorizontalHeaderView{
syncView: tableView
}
TableView {
id: tableView
model: myModel
}
}
The HorizontalHeaderView will use what you provide in your model with headerData.

How to display values from lists in a UI QML (QT) inside a Repeater

I've been facing this issue for days without coming to a conclusion, I hope someone could give me some useful hints to solve it.
I'll try to simplify the issue with an example:
In my C++ code I defined the class MyObjectModel that will act
later as a model in the Repeater block in my main ui.qml file.
MyObjectModel is visible to the QQmlApplicationEngine.
MyObjectModel
has 2 attributes (lists) : xCoordinatesList and yCoordinatesList.
They represent the x and y pixel coordinates of a list of points.
I.e. xCoordinatesList = [100, 200], yCoordinatesList = [10, 20] mean logically that I have 2 points with the following pixel coordinates that I want to display on the screen: (100,10), (10,20).
The xCoordinatesList and yCoordinatesList are Roles of my model
for the QML engine. This means for instance that in a common
.qml file i can clearly print the content of xCoordinatesList by
typing:
Component.onCompleted
{
console.log("x coordinates: ",xCoordinatesList);
}
The question is: how can I display at the same time the list of points on the screen?
If I want to display only one dot (so one couple of coordinates) my code works. I really don't know how to extend it to make it print all of them.
In my MainForm.ui.qml I defined a Repeater inside a Rectangle :
Rectangle
{
....
Repeater
{
model: dotModel
delegate:
DotItem
{
id: dotItem;
objectName: "dotItem";
DotPositionOnMap
{
id: dotPositionId;
objectWidth: dotItem.width;
objectHeight: dotItem.height;
}
x: dotPositionId.xPositionOnMap;
y: dotPositionId.yPositionOnMap;
}
}
....
}
I need a Repeater because MyObjectModel which holds the two lists of x and y coordinates can dynamically change over time.
dotModel is just a fake model I use for an other purpose.
DotItem is my qml Item that identifies the red dot circle image I want to depict on the screen for each couple of elements in xCoordinatesList, yCoordinatesList.
DotItem.ui.qml
import QtQuick 2.4
import QtQuick.Layouts 1.1
Item
{
width: 10
height: 10
opacity: 1
Image
{
id: dotItemImage
anchors.fill: parent
source: "red_dot.png"
}
}
red_dot.png image should be displayed for each point depicted on the screen.
DotPositionOnMap.qml is responsible for computing the right x and y pixel position on the screen.
import QtQuick 2.5
import "calcCurrentPos_script.js" as CurrentPos
Item
{
// Values filled from MainForm.ui.qml
property int objectWidth
property int objectHeight
// Getting current coordinates
// Fetching element 0 from both lists
property real currentx: CurrentPos.getCurrentxPoint(0);
property real currenty: CurrentPos.getCurrentyPoint(0);
// Generating the x and y pixel position on map.
// Toy example
property int xPositionOnMap : currentx-(objectWidth/2);
property int yPositionOnMap : currenty-(objectHeight/2);
}
Where calcCurrentPos_script.js
function getCurrentxPoint(val)
{
return xCoordinatesList[val];
}
function getCurrentyPoint(val)
{
return yCoordinatesList[val];
}
In this way I can only display one dot on the screen since I specify in DotPositionOnMap.qml which point to fetch:
// Fetching element 0 in this case
property real currentx: CurrentPos.getCurrentxPoint(0);
property real currenty: CurrentPos.getCurrentyPoint(0);
I used javascript for this attempt because I thought I could use a for loop to scan all the elements to be displayed, but it didn't work.
Extract of my model
QVariant MyModelObject::data(const QModelIndex& index, int role) const
{
const MyModelObject& object = objects.values().value(index.row());
....
if(role == XRole)
{
QList<TrackPoint> tkrList = object.getList();
QList<QVariant> tkrVariantList;
for(auto track: trackpointList)
{
tkrVariantList.append(track.getPosition().getX());
}
return QVariant(tkrVariantList);
}
else if(role == YRole)
{
QList<TrackPoint> tkrList = object.getList();
QList<QVariant> tkrVariantList;
for(auto track: trackpointList)
{
tkrVariantList.append(track.getPosition().getY());
}
return QVariant(tkrVariantList);
}
}
....
....
QHash<int, QByteArray> MyModelObject::roleNames() const
{
QHash<int, QByteArray> roles;
roles[XRole] = "xCoordinatesList";
roles[YRole] = "yCoordinatesList";
return roles;
}
I truly appreciate any ideas concerning the generalisation of this implementation.
Thank you
The Qt documentation is very clear. The first you have to read is that article. I think that in your case the simpliest way is list-based model. Or, of cource, you can subclass QAbstractListModel.
Your question is not so clear and you didn't provide the code of your model but maybe this small example will help you:
Declaration
class MyModel : public QAbstractListModel
{
Q_OBJECT
public:
enum PointRoles {
XRole = Qt::UserRole + 1,
YRole
};
MyModel(QObject *parent = Q_NULLPTR);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QHash<int, QByteArray> roleNames() const;
private:
QList<QPoint> m_list;
};
Implementation
MyModel::MyModel(QObject *parent) :
QAbstractListModel(parent)
{
}
QHash<int, QByteArray> MyModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[XRole] = "xcoord";
roles[YRole] = "ycoord";
return roles;
}
int MyModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_list.count();
}
QVariant MyModel::data(const QModelIndex &index, int role) const
{
if(role == XRole)
return m_list[index.row()].x();
else if(role == YRole)
return m_list[index.row()].y();
return QVariant();
}
Registation
qmlRegisterType<MyModel>("qt.test", 1, 0, "PointModel");
Usage
Window {
visible: true
width: 800
height: 800
PointModel {id: mymodel}
Repeater {
model: mymodel
delegate: Rectangle {
x: 100 + xcoord
y: 100 + ycoord
width: 20
height: 20
color: "red"
radius: 10
}
}
}
* SOLVED *
In your main.qml you can have something like this, which handles the global drawing routine.
Repeater
{
model: dotModel
delegate:
DotPositionOnMap{}
}
DotPositionOnMap.qml will read the list of x and y coordinates and for each element of both will create a dot Item object which will be displayed on the screen.
import QtQuick 2.5
Item
{
id: dotPositionOnMap
objectName: "dotoPositionOnMap"
Component.onCompleted:
{
// yCoordinatesList would have given the same result
var dotListLength = xCoordinatesList.length;
// Dot properties can by handled dynamically
var dotWidth = 5;
var dotHeight = 5;
var dotRadius = 10;
var dotColor = "red"
// For each entry of xCoordinatesList and yCoordinatesList
// I generate a DotShape qml object that will display a dot on the screen
for(var i = 0; i < dotListLength; i++)
{
var currentXValue = xCoordinatesList[i];
var currentYValue = yCoordinatesList[i];
// x and y pixrl values for a DotShape.qml instance
var xPositionOnMap = currentXValue-(dotWidth/2);
var yPositionOnMap = currentYValue-(dotHeight/2);
// Creating DotShape.qml component
var comp = Qt.createComponent("DotShape.qml");
var dotComponent = comp.createObject(dotPositionOnMap,
{
"x": xPositionOnMap,
"y": yPositionOnMap,
"width": dotWidth,
"height": dotHeight,
"color": dotColor,
"radius": dotRadius
});
} // end for
} // end script
} // end Item
Finally DotShape.qml , which's just a small red dot plotted at x,y coordinate
import QtQuick 2.5
Rectangle
{
// Other properties are generated at runtime
id: dotShapeId;
objectName: "dotShapeId";
}

QML/C++ model - view separation: data in C++, multiple lists displaying this data in QML

I am trying to strictly separate the data (in C++) from the visualization (lists in QML). On the model side, data is stored in instances of a C++ class (Data.cpp) and pointers to that instances are arranged in two lists (completeList and selectedList) by another C++ class (Parser.cpp). Those two lists should be displayed in QML, with the following restrictions:
the data in completeList is displayed in different QML ListViews (for example according to the name)
this separation must be done in QML, not by Parses.cpp (which only provides the complete list)
it must be possible to add list items from completeList to selectedList (for example by clicking on it)
if values of Data are changed in one ListView, the Data itself and the other views displaying this Data should change accordingly
Thanks to ksimons, I found a way to do half of it, but I cant figure out the rest. Here is what I got so far:
Data.h
class Data : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
Data(const QString &n) : _name(n) { }
QString name() const { return _name; }
void setName(const QString &n) {
if (_name == n)
return;
_name = n;
emit nameChanged(n);
}
signals:
void nameChanged(const QString &n);
private:
QString _name;
};
Parser.h
class Parser : public QObject
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Data> completeList READ completeList CONSTANT)
Q_PROPERTY(QQmlListProperty<Data> selectedList READ selectedList CONSTANT)
public:
Parser(QObject *parent = 0) {
Data* d1 = new Data(QStringLiteral("a1"));
Data* d2 = new Data(QStringLiteral("a2"));
Data* d3 = new Data(QStringLiteral("a3"));
Data* d4 = new Data(QStringLiteral("b1"));
Data* d5 = new Data(QStringLiteral("b2"));
_completeList.append(d1);
_completeList.append(d2);
_completeList.append(d3);
_completeList.append(d4);
_completeList.append(d5);
_selectedList.append(d1);
_selectedList.append(d4);
}
QQmlListProperty<Data> completeList() {
return QQmlListProperty<Data>(this, _completeList);
}
QQmlListProperty<Data> selectedList() {
return QQmlListProperty<Data>(this, _selectedList);
}
private:
QList<Data*> _completedList;
QList<Data*> _selectedList;
};
QML part:
ListView
{
id: startsWithA
anchors.fill: parent
delegate: delegateItem
}
ListView
{
id: startsWithB
anchors.fill: parent
delegate: delegateItem
}
ListView
{
id: selectedData
anchors.fill: parent
delegate: delegateItem
}
Item
{
id: delegateItem
height: 30
width: parent.width
Text { text: name }
MouseArea { //change name of corresponding Data and other views accordingly
anchors.fill: parent
onClicked: model.name = "newName";} //does not work
MouseArea { //add to selectedList in Parser
anchors.fill: parent
onClicked: ?????? }
}
Component.onCompleted:
{
selectedData.model = parser.seletedList;
var listAll = parser.completeList;
var listA, listB;
for(var i=0; i<listAll.length; i++)
{
if(listAll[i].name.charAt(0) == 'a')
{
//changing values in startsWithA does not affect anything else with that :(
listA.append(listAll[i]);
}
else if(listAll[i].name.charAt(0) == 'b')
{
//changing values in startsWithB does not affect anything else with that :(
listB.append(listAll[i]);
}
//...
}
startsWithA.model = listA;
startsWithB.model = listB;
//...
}
I hope this question is not to specific and somebody can help me. Thank you in advance.

Qt Model within a model?

I have a Qt model which could very well be a QAbstractListModel. Each "row" represents an object I have stored in a QList. I'm displaying this in QML in a ListView. However, each object has one property that happens to be an array of strings. I would like to display this as a ListView within the delegate that displays that row. But I don't know how to expose that model (for the string array property of the object) to QML. I can't expose it through the data function since Models are QObjects, which cannot be QVariants. I thought of using QAbstractItemModel instead, but I still don't know how to get a model for my ListView. In case it matters, I'm using Qt 5.0.0 release.
You can return QVariantList from your main QAbstractListModel and this can then be assigned as a model to your internal ListView that you have in the delegate. I have added a small example that has a very simple one row model with internal model as an example.
The c++ model class:
class TestModel : public QAbstractListModel
{
public:
enum EventRoles {
StringRole = Qt::UserRole + 1
};
TestModel()
{
m_roles[ StringRole] = "stringList";
setRoleNames(m_roles);
}
int rowCount(const QModelIndex & = QModelIndex()) const
{
return 1;
}
QVariant data(const QModelIndex &index, int role) const
{
if(role == StringRole)
{
QVariantList list;
list.append("string1");
list.append("string2");
return list;
}
}
QHash<int, QByteArray> m_roles;
};
Now you can set this model to QML and use it like this:
ListView {
anchors.fill: parent
model: theModel //this is your main model
delegate:
Rectangle {
height: 100
width: 100
color: "red"
ListView {
anchors.fill: parent
model: stringList //the internal QVariantList
delegate: Rectangle {
width: 50
height: 50
color: "green"
border.color: "black"
Text {
text: modelData //role to get data from internal model
}
}
}
}
}