I am relatively new to QT, so any help would be greatly appreciated!
I am working on a Qt Quick Application, making use of the QQmlApplicationEngine for the UI. I made a subclass of QAbstractTableModel and implemented the necessary functions and successfully created and displayed a (singular) table on the Window.
Currently, how I linked the model in the QML file is by setting the context property of the root property of QQmlApplicationEngine.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSharedPointer>
#include <QQmlContext>
#include "tablecontroller.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QSharedPointer<QQmlApplicationEngine> engine =
QSharedPointer<QQmlApplicationEngine>::create();
TableController theController(engine.toWeakRef());
engine.data()->rootContext()->setContextProperty("TableController", &theController);
engine.data()->load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
tabcontroller.h
#ifndef TABLECONTROLLER_H
#define TABLECONTROLLER_H
#include <QObject>
#include <QQmlApplicationEngine>
#include <QWeakPointer>
#include <QHash>
#include <QList>
#include "tablemodel.h"
class TableController : public QObject
{
Q_OBJECT
public:
explicit TableController(QWeakPointer<QQmlApplicationEngine> Engine, QObject *parent = 0);
Q_INVOKABLE void AddEntry();
signals:
public slots:
private:
TE::TDT::TableModel m_TableModel;
QList<QString> m_Headings;
};
#endif // TABLECONTROLLER_H
tabcontroller.cpp
#include "tablecontroller.h"
#include <QQmlContext>
TableController::TableController(QWeakPointer<QQmlApplicationEngine> Engine, QObject *parent) : QObject(parent)
{
m_Headings << "Heading1" << "Heading2" << "Heading3" << "Heading4";
m_TableModel.setColumnHeadings(m_Headings);
Engine.data()->rootContext()->setContextProperty("myModel", &m_TableModel);
}
void TableController::AddEntry()
{
QHash<QString, QVariant> tempHash;
int counter = 1;
for (auto x : m_Headings)
{
tempHash.insert(x, QString::number(counter));
counter++;
}
m_TableModel.addElement(tempHash);
}
tablemodel.h
#ifndef TABLEMODEL_H
#define TABLEMODEL_H
#include <QObject>
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include <QList>
#include <QString>
#include <QHash>
namespace TE {
namespace TDT {
class TableModel : public QAbstractTableModel
{
Q_OBJECT
Q_PROPERTY(QStringList userRoleNames READ userRoleNames CONSTANT)
public:
explicit TableModel(QObject *parent = 0);
enum MyModelRoles {
UserRole1 = Qt::UserRole + 1,
UserRole2,
};
void setFirstColumn(const QList<QString> &FirstColumn);
void setColumnHeadings(const QList<QString> &ColumnHeadings);
void addElement(const QHash<QString, QVariant> Entry);
QStringList userRoleNames();
signals:
public slots:
// QAbstractTableModel interface
public:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QHash<int, QByteArray> roleNames() const override;
private:
QList<QHash<QString, QVariant>> m_TableData;
QList<QString> m_ColumnHeadings;
QMap<int, QString> m_roleNames;
};
}// TDT
}// TE
#endif // TABLEMODEL_H
tablemodel.cpp
#include "tablemodel.h"
#include <QDebug>
#include <QAbstractListModel>
TE::TDT::TableModel::TableModel(QObject *parent) : QAbstractTableModel(parent)
{
}
int TE::TDT::TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_TableData.count();
}
int TE::TDT::TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_ColumnHeadings.count();
}
QVariant TE::TDT::TableModel::data(const QModelIndex &index, int role) const
{
QVariant retVal;
try {
if(!index.isValid())
{
throw QString("Invalid index for inherited data function");
}
// Check row index
if(index.row() >= m_TableData.count() || index.row() < 0)
{
throw QString("Index (row) out of bounds for data function");
}
//Check column index
if(index.column() >= m_ColumnHeadings.count() || index.column() < 0)
{
throw QString("Index (column) out of bounds for data function");
}
QList<int> keys = m_roleNames.keys();
if(role == Qt::DisplayRole || role == Qt::EditRole)
{
QString colKey = m_ColumnHeadings.at(index.column());
if (m_TableData.at(index.row()).value(colKey).isNull())
{
retVal = QVariant();
} else {
retVal = m_TableData.at(index.row()).value(colKey);
}
} else if (m_roleNames.keys().contains(role)) {
QHash<QString, QVariant> temp1 = m_TableData.at(index.row());
retVal = m_TableData.at(index.row()).value(m_roleNames.value(role));
}
return retVal;
} catch (QString &e) {
qDebug() << e;
return QVariant();
}
}
QVariant TE::TDT::TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
Q_UNUSED(orientation);
QVariant retVal;
if (role == Qt::DisplayRole)
{
retVal = m_ColumnHeadings.at(section);
}
return retVal;
}
QHash<int, QByteArray> TE::TDT::TableModel::roleNames() const {
// Populate the roles - basically the column headings
QHash<int, QByteArray> roles = QAbstractTableModel::roleNames();
// Should not overwrite existing roles
int LastIndexOfUserRole = Qt::UserRole;
for (int x = 1; x <= m_ColumnHeadings.count(); x++)
{
roles[LastIndexOfUserRole + x] = m_ColumnHeadings.at(x-1).toUtf8();
}
return roles;
}
QStringList TE::TDT::TableModel::userRoleNames() // Return ordered List of user-defined roles
{
QHashIterator<int, QByteArray> i(roleNames());
while (i.hasNext())
{
i.next();
if(i.key() > Qt::UserRole)
{
m_roleNames[i.key()] = i.value();
}
}
return m_roleNames.values();
}
void TE::TDT::TableModel::setColumnHeadings(const QList<QString> &ColumnHeadings)
{
m_ColumnHeadings = ColumnHeadings;
}
void TE::TDT::TableModel::addElement(const QHash<QString, QVariant> Entry)
{
beginInsertRows(QModelIndex(), this->rowCount(QModelIndex()), this->rowCount(QModelIndex()));
m_TableData.append(Entry);
endInsertRows();
}
main.qml import QtQuick 2.5 import QtQuick.Window 2.2 import QtQuick.Controls 1.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: mainwindow
// template component for the column headings
Component
{
id: columnComponent
TableViewColumn{width: 100 }
}
TableView {
id: tableview
height: mainwindow.height - 50
width: mainwindow.width
y: 5
x: 0
visible: true
resources:
{
var roleList = myModel.userRoleNames
var temp = []
for(var i = 0; i < roleList.length; i++)
{
var role = roleList[i]
temp.push(columnComponent.createObject(tableview, { "role": role, "title": role}))
}
return temp
}
model: myModel
}
Rectangle {
id: abutton
anchors.top: tableview.bottom
height: 40
width: mainwindow.width
Text {
text: "Click to Add"
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
TableController.AddEntry()
}
}
}
}
Code adapted from: QML TableView with dynamic number of columns
Now, my question is, if I wanted to re-use the TableView as that defined in the main.qml I want to use another model for it. The problem is (from my limited understanding) that the "variable" that the model in the QML links to is static (defined at start-up), in this case, "myModel".
How can I change the model once I create another instance of this TableView? Will I have to link another "variable" every time?
I have tried to cast the TableView (in QML) to a QQuickItem (in c++) and trying to set the property there, to no avail (gives a null, but also QQuickItem doesn't have a "setModel" function)
Sorry for the long post, wanted to give as much information as possible.
https://stackoverflow.com/a/35755172/7094339
This guy saved my life :D So it appears I needed to use the component.beginCreate() function.