0

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:

Results of executing the previous code.

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.

  • 1
    remove `qmlRegisterType("TableModel", 1, 0, "TableModel");`. Also provide a [mre]. Also add `qDebug() << tableModel.rowCount();` after `tableModel.setQuery(MySQLQueries::queryBodyOfVCF.arg(1), db.db);` – eyllanesc Mar 03 '21 at 19:47
  • Thanks. ```qDebug() << tableModel.rowCount();``` returns 1 (as expected, since MySQL workbench returns only one row as well). Removing ```qmlRegisterType("TableModel", 1, 0, "TableModel");``` does not solve the problem, but I understand why you told me to remove it. – Alberto Casas Ortiz Mar 03 '21 at 20:58
  • 1
    mmm, I already understood the error. I thought that the error was the number of rows since in the image it shows 1 but in the expected output it shows 2. Now I understand that the error is because it appears TABLEVIEW_QMLTYPE_.... – eyllanesc Mar 03 '21 at 22:41
  • My fault, I wasn't clear there. I have edited the question so it is clear that that's an output example. I have inserted another entry in the database so the query is now returning 2 rows in MySQL Workbench. ```qDebug() << tableModel.rowCount();``` is printing 2. However, the output in the GUI is exactly the same, with just one row showing ```TABLEVIEW_QMLTYPE_46...()```, and the functions ```data``` and ```roleNames``` are not being executed. – Alberto Casas Ortiz Mar 03 '21 at 22:50

1 Answers1

1

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.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Works like a charm! Thank you so much. The problem then was that it was using the Type instead of the object. Sure, I will check the model implemented in the post you linked and change my implementation. The truth is that it has been a little difficult finding examples for this, so thank you for the link. – Alberto Casas Ortiz Mar 04 '21 at 02:21