Unable to read data from QSqlTableModel in Qml : "role names" are not defined
-
So I subclassed
QSqlTableModel
in my application. Then I set this model as a context property to be accessible in QML assigning it to aListView
. Then I set a simpleLabel
as a delegate withtext
set to my role name (e.g. Name), but I always get the following error:ReferenceError: Name is not defined
Below is my code
#include "sqlmodel.h" #include <QSqlDatabase> #include <QSqlError> #include <QSqlRecord> #include <QStandardPaths> #include <QSqlQuery> SqlModel::SqlModel(QObject *parent ) : QSqlTableModel( parent ) { openDataBase(); } QVariant SqlModel::data(const QModelIndex &index, int role) const{ QVariant value; if(role < Qt::UserRole) { value = QSqlTableModel::data(index, role); } else { int columnIdx = role - Qt::UserRole - 1; QModelIndex modelIndex = this->index(index.row(), columnIdx); value = QSqlTableModel::data(modelIndex, Qt::DisplayRole); } return value; } QHash<int, QByteArray> SqlModel::roleNames() const { // QHash<int, QByteArray> roles; // roles[Qt::UserRole + 1] = "Identifier"; // roles[Qt::UserRole + 2] = "Name"; // roles[Qt::UserRole + 3] = "ElementColor"; // roles[Qt::UserRole + 4] = "FileUrl"; // roles[Qt::UserRole + 5] = "HomeRss"; // roles[Qt::UserRole + 6] = "ListPos"; // return roles; QHash<int, QByteArray> roles; for (int i = 0; i < this->columnCount(); i++) { QString role= this->headerData(i, Qt::Horizontal).toString(); qDebug() << role; roles[Qt::UserRole + i + 1] = QVariant(role).toByteArray(); qDebug()<<this->headerData(i, Qt::Horizontal); } return roles; } bool SqlModel::insertItem(const QVariantMap itemMap) { QSqlRecord sqlRecord = this->record(); sqlRecord.setValue("Identifier", itemMap.value("Identifier").toInt()); sqlRecord.setValue("Name", itemMap.value("Name").toString()); sqlRecord.setValue("ElementColor", itemMap.value("ElementColor").toString()); sqlRecord.setValue("FileUrl", itemMap.value("FileUrl").toString()); sqlRecord.setValue("HomeRss", itemMap.value("HomeRss").toString()); sqlRecord.setValue("ListPos", itemMap.value("ListPos").toInt()); bool success = this->insertRecord(rowCount(), sqlRecord); if(!success) qWarning() << "UNABLE TO ADD ITEM TO DATABASE" << this->lastError().text(); else{ this->submit(); } } void SqlModel::openDataBase() { QSqlDatabase db; const QString DRIVER("QSQLITE"); if(QSqlDatabase::isDriverAvailable(DRIVER)) { db = QSqlDatabase::addDatabase(DRIVER); QString storagePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); db.setDatabaseName(storagePath+"/database.sqlite"); if(!db.open()) qWarning() << "ERROR: " << db.lastError(); else{ qDebug( "Opening database %s", qPrintable( db.databaseName() ) ); QSqlQuery query("CREATE TABLE IF NOT EXISTS home (Identifier INTEGER PRIMARY KEY," "Name TEXT, " "ElementColor TEXT, " "FileUrl TEXT, " "HomeRss TEXT, " "ListPos INTEGER)"); if(!query.exec()) qWarning() << "DATABASE ERROR: " << query.lastError().text(); this->setTable("home"); this->setEditStrategy(QSqlTableModel::OnManualSubmit); this->select(); } } else{ qWarning() << "SQL DRIVER " << DRIVER << "NOT AVAILBLE" << db.lastError(); } }
-
Hi,
Did you already saw that wiki entry about that subject ?
-
@SGaist said in Unable to read data from QSqlTableModel in Qml : "role names" are not defined:
Hi,
Did you already saw that wiki entry about that subject ?
Yeah, my code is partially based on that
-
Then can you also share the QtQuick part so your code can be properly tested ?
-
@SGaist yeah sure this is my qml:
import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.4 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Scroll") ColumnLayout{ anchors.fill: parent ScrollView { Layout.fillWidth: true Layout.fillHeight: true ListView { width: parent.width model: sqlModel delegate: ItemDelegate { text: "Item" + (Name) // if you remove (Name) and just put a string, then add it shows the string width: parent.width } } } Button{ z: 15 text: "Add" onClicked:{ var milliseconds = new Date().getTime(); var myObject = {Identifier: milliseconds, Name: "MyItem", ElementColor: "blue", FileUrl: "http://", HomeRss: "http:??", ListPos: 0} sqlModel.insertItem(myObject) } } } }
-
I didn't realise, there missing parts like your model header and the main.cpp file.
Is your project accessible somewhere ?
-
@SGaist said in Unable to read data from QSqlTableModel in Qml : "role names" are not defined:
I didn't realise, there missing parts like your model header and the main.cpp file.
Is your project accessible somewhere ?
Unfortunately not but the header and main file implementation is quite simple. Here is the header:
#include <QObject> #include <QDebug> #include <QSqlTableModel> #include <QQmlAutoPropertyHelpers.h> class SqlModel : public QSqlTableModel { Q_OBJECT public: SqlModel(QObject* parent = nullptr); Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override; QHash<int, QByteArray> roleNames() const override; Q_INVOKABLE bool insertItem(const QVariantMap itemMap); private: void openDataBase(); };
In my
main.cpp
I do the following:#include "sqlmodel.h" #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); app.setOrganizationDomain("daljit97"); qmlRegisterType<SqlModel>(); SqlModel *sqlHomeModel = new SqlModel(); QQmlApplicationEngine engine; QQuickStyle::setStyle("Material"); QQmlContext *qmlContext = engine.rootContext(); qmlContext->setContextProperty("sqlHomeModel", sqlHomeModel); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
-
Sorry but with the current bits and pieces I don't have anything on screen. Can you maybe refactor that to ensure it goes up to the screen ?
-
@SGaist Here I uploaded a fully working project where the problem persists https://www.dropbox.com/s/qsyqds61zxdxkyx/SqlModelTest.zip?dl=0.
When you click the add button, it shows:Name not defined
.
EDIT: I also update the qml file example provided here -
That's because you are creating your database connection after you created your model. So the model is using the default database connection that hasn't been created yet.
Move the database initialisation part outside of your model and somewhere before your create that object.