Bind QAbstractTableModel To QML
-
Hello,
I'm relatively new to Qt and I'm struggling to display data in a TableView using a QAbstractTableModel.
I have create a sample application that has a MyTableModel class that inherits from the QAbstractTableModel and implements the methods that I believe are necessary. This class has a QList of MyDataObjects (which is a dummy object containing some strings). My intentions is to show a MyDataObject on each line with its properties in different colums, so the number of colums is fixed.
The problem is that the data is not shown in the TableView (but the rows are added as a scrollbar appears, when adding the rows).
The post is quite long but most of it are code samples.My QAbstractTablemodel looks like this
@
class MyTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit MyTableModel(QObject *parent = 0);//functions implementing the Abstract table model int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; bool insertRows(int row , int count, const QModelIndex & parent = QModelIndex()); //function that can be called from UI to fill the mData variable with some dummy data Q_INVOKABLE void fillTable();
private:
QList<MyDataObject *> mData;};
@The implementation of rowCount is straightforward:
@
int MyTableModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0; //according to the documentation we should return 0 in this case
return mData.count(); //the number of entries in the table
}
@The implementations of "data" and "headerData" are irrelevant as they are NEVER executed (which is the problem of course). columnCount is the same as rowCount but returns 3 instead of mData.count, columnCount is also never executed
The implementation of insertRows is like this (and it basically adds new MyDataObjects, to "mData"):
@bool MyTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
beginResetModel();
// I have also tried beginInsertRows(parent, row, row+count-1 );for (int i = 0; i < count;i++) mData.insert(row +i, new MyDataObject("A "+ i, "B " + i, "C " + i)); // I have also tried endInsertRows(); endResetModel(); return true;
}@
The function fillTable, maybe this is where I go wrong, should i pass something to the QModelIndex parameter?:
@void MyTableModel::fillTable()
{insertRows(0,100);
}@
Finally this is how I start the application:
@int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;MyTableModel* model = new MyTableModel(); engine.rootContext()->setContextProperty("table", model); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec();
}@
And the main.qml looks like this:
@ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")menuBar: MenuBar { Menu { title: qsTr("File") MenuItem{ text: "Fill Table"; onTriggered: table.fillTable(); } MenuItem { text: qsTr("Exit") onTriggered: Qt.quit(); } } } TableView { model: table anchors.margins: 12 anchors.fill: parent }
}@
-
Update:
First the previous posted code contains some errors when workin with strings, never mind them (this was just me using 21st century style syntax (java, c#,.......) on ancient c things).
I've looked into this matter further and have come to the following conclusion: there's nothing wrong with the model itself, only with the binding of the model to the qml
If created a more traditional QtWidgets main window (that inherits from QMainWindow), and using the same model as before everything works. The MainWindow class looks like this:
@MainWindow::MainWindow()
{
model = new MyTableModel(this);view = new QTableView; view->setShowGrid(false); view->horizontalHeader()->show(); view->verticalHeader()->show(); view->setModel(model); QMenu *fileMenu = new QMenu(tr("&File"), this); QAction *fillDataAction = fileMenu->addAction(tr("&Fill Data...")); menuBar()->addMenu(fileMenu); connect(fillDataAction, SIGNAL(triggered()), this, SLOT(fillData())); setCentralWidget(view); setWindowTitle(tr("Test model")); resize(640, 480);
}
void MainWindow::fillData()
{
QList<MyDataObject *> data;
for (int i = 0; i < 100;i++)
{
QString nr = QString::number(i);
data.append(new MyDataObject(QString("A ").append(nr), QString("B ").append(nr), QString("C ").append(nr)));
}
model->fillTable(data);
}
@But by using this approach the flexibility of Qt Quick/ Qml gets lost. So I have also tried to implement this into a Qt Quick/Qml based approach. But this has failed. The main differences between the Qt Widgets and the Qt Quick application are:
-With Qt Widgets we use QTableView, in Qml this is TableView, are they the same? (I believe they are but I can be wrong).
- If they are the same, is there a difference between calling the setModel function in C++ and setting the model on the tableview in Qml.
And if there is no difference, than why does one work while the other doesn't.
Any help would be greatly appreciated.
The main two differences between the QML and
-
Hi and welcome to devnet,
You need a bit more work to integrate a C++ model with QML
See "here":http://qt-project.org/wiki/QML_and_QSqlTableModel
Hope it helps
-
OK, thanks for the reply,
Finally figured this out, an ever better link is "this":http://qt-project.org/doc/qt-4.8/qdeclarativemodels.html one.
The problem is that this is written for Qt 4.8 as much of the documentation is. So in the animals example you need to make some changes (but if you look to the abstractitemmodel example in qt creator you'll find it).
Bottom line: I got totally confused by the fact that the "detailed description" on the QAbstractItemModel, does not contain any indication that the rolenames are used for QML (but I understand that keeping all information up to date is an imossible job).