How to Use a QSqlQueryModel in QML
2016-10-31 22:48
519 查看
How to Use a QSqlQueryModel in QML
(Redirected from How to use a QSqlQueryModelin QML)
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine. Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean. |
Contents
[hide] 1 How
to use a QSqlQueryModel in QML
1.1 Initial
fully detailed approach
1.2 A
more generic approach
How to use a QSqlQueryModel in QML
Initial fully detailed approach
Introduction
The software I develop, Photo Parata, is a client server application that uses a sql backend. Most of the time the data Photo Parata displays requires some joins. Because of this, most ofthe time the models are derived from QSqlQueryModel, not QSqlTableModel. For QSqlRelationalTableModel, you can find an working but unexplained example athttp://wiki.qt.io/QML_and_QSqlTableModel
In this how to, I will walk you through the steps of setting up a custom model for QML, derived from QSqlQueryModel.
I would like to thank Christophe
Dumez for his blog How to use C++ list model in
QML. It was this blog that allowed me to piece the following together.
Other useful sources were : Using_QStandardItemModel_in_QML
(wiki page) and QSqlTableModel in QML (forum thread)
The data source for this example was lifted from one of the Sql examples that ships with Qt, examples\sql\masterdetail
Step 1: Create a C++ class that derives from QSqlQueryModel:
All the magic happens in the constructor and in the overloaded data() method.class ArtistsSqlModel : public QSqlQueryModel { Q_OBJECT public: explicit ArtistsSqlModel(QObject *parent); void refresh(); QVariant data(const QModelIndex &index, int role) const; signals: public slots: private: const static char* COLUMN_NAMES[]; const static char* SQL_SELECT; };
Step 2: Implement two static constants
I always have two constant static variables in each of my models that derive from QSqlQueryModel, COLUMN_NAMES and SQL_SELECT. The order of the column names in COLUMN_NAMES must match theorder they are listed in the SELECT statement
const char* ArtistsSqlModel::COLUMN_NAMES[] = { "artist", "title", "year", NULL }; const char* ArtistsSqlModel::SQL_SELECT = "SELECT artists.artist, albums.title, albums.year" " FROM albums" " JOIN artists ON albums.artistid = artists.id";
Step 3: Set the roleNames in the constructor
This is where all the magic really happens. The QML will reference the different columns by the role names set on the model.ArtistsSqlModel::ArtistsSqlModel(QObject *parent) : QSqlQueryModel(parent) { int idx = 0; QHash<int, QByteArray> roleNames; while( COLUMN_NAMES[idx]) { roleNames[Qt::UserRole + idx + 1] = COLUMN_NAMES[idx]; idx++; } setRoleNames(roleNames); refresh(); }
Step 4: implement the data() method and the refresh() method:
As long as the role that is requested is not a user role, return the default. But if the role is a user role, return the correct column:QVariant ArtistsSqlModel::data(const QModelIndex &index, int role) const { QVariant value = QSqlQueryModel::data(index, role); if(role < Qt::UserRole) { value = QSqlQueryModel::data(index, role); } else { int columnIdx = role - Qt::UserRole - 1; QModelIndex modelIndex = this->index(index.row(), columnIdx); value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole); } return value; }
The refresh() method is the most important, without it, the model won't show anything at all. The best is to stick to the setQuery method from QSqlQueryModel.
void ArtistsSqlModel::refresh() { this->setQuery(SQL_SELECT); }
Step 5: Allow QML to see the model:
Create an instance of the model (make note that the constructor of the model did query the DB the first time). Then set it as a property on the viewer’s context, in this case I called itartistModel:
ArtistsSqlModel *artistsSqlModel = new ArtistsSqlModel( qApp); QmlApplicationViewer viewer; viewer.rootContext()->setContextProperty("artistsModel", artistsSqlModel); viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto); viewer.setMainQmlFile(QLatin1String("qml/SQLListView/main.qml")); viewer.showExpanded();
Step 6: Create the QML list
Since the model was exposed in step 5, the model exists and is ready to be used in QML. Simply set the model of the ListView to the name give in step 5.import QtQuick 1.1 Rectangle { width: 500 height: 500 MouseArea { anchors.fill: parent Text { id: text1 anchors.verticalCenterOffset: 20 anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Testing") font.pixelSize: 12 } ListView { id: list_view1 x: 125 y: 100 width: 110 height: 160 delegate: ArtistItemDelegate {} model: artistsModel } } }
Step 7: Create the QML delegate used by the list
And finally implementation of the delegate. Notice here how the names set in the roleModel are used as the values to bind to the text property of the Text objects:ArtistItemDelegate.qml
import QtQuick 1.1 Item { id: delegate width: delegate.ListView.view.width; height: 30 clip: true anchors.margins: 4 Row { anchors.margins: 4 anchors.fill: parent spacing: 4; Text { text: artist width: 150 } Text { text: title width: 300; } Text { text: year width: 50; } } }
Source code is no longer available on my website, so feel free to contact me for the complete source code, I will be happy to share!
A more generic approach
Based on the initial wiki article I came up with a more generic approach that allow to use the same class for all your models instead of creating a derived class for each model.Here it is :
sqlquerymodel.h
#pragma once #include <QSqlQueryModel> class SqlQueryModel : public QSqlQueryModel { Q_OBJECT public: explicit SqlQueryModel(QObject *parent = 0); void setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase()); void setQuery(const QSqlQuery &query); QVariant data(const QModelIndex &index, int role) const; QHash<int, QByteArray> roleNames() const { return m_roleNames; } private: void generateRoleNames(); QHash<int, QByteArray> m_roleNames; };
sqlquerymodel.cpp
#include "SqlQueryModel.h" #include <QSqlRecord> #include <QSqlField> SqlQueryModel::SqlQueryModel(QObject *parent) : QSqlQueryModel(parent) { } void SqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db) { QSqlQueryModel::setQuery(query, db); generateRoleNames(); } void SqlQueryModel::setQuery(const QSqlQuery & query) { QSqlQueryModel::setQuery(query); generateRoleNames(); } void SqlQueryModel::generateRoleNames() { m_roleNames.clear(); for( int i = 0; i < record().count(); i ++) { m_roleNames.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8()); } } QVariant SqlQueryModel::data(const QModelIndex &index, int role) const { QVariant value; if(role < Qt::UserRole) { value = QSqlQueryModel::data(index, role); } else { int columnIdx = role - Qt::UserRole - 1; QModelIndex modelIndex = this->index(index.row(), columnIdx); value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole); } return value; }
And use it like this :
SqlQueryModel *model1 = new SqlQueryModel(0); model1->setQuery("SELECT * FROM table WHERE column='value'"); SqlQueryModel *model2 = new SqlQueryModel(0); model2->setQuery("SELECT * FROM anothertable WHERE anothercolumn='value'"); QmlApplicationViewer viewer; viewer.rootContext()->setContextProperty("myFirstModel", model1); viewer.rootContext()->setContextProperty("mySecondModel", model2);
Categories:
Articles needing cleanup
HowTo
Developing with Qt
相关文章推荐
- How to Use Lambda Expressions in a Query
- how to use trained object detection model in tensorflow
- How to use tensorflow pre-trained model in Android
- Applications Programming in Smalltalk-80(TM):How to use Model-View-Controller (MVC)
- How and Why to use the System.servicemodel.MessageParameterAttribute in WCF
- How to use virtual path providers to dynamically load and compile content from virtual paths in
- How to use enumerations in Profile?
- How to use AspnetUpload™ in your web application
- How to use the class in assembly in XAML
- how to use danymic sql in SQL Server 2000
- How to Use the restrict Qualifier in C
- How to use an Outlook Object Model from Visual C++ by using a #import statement
- how to use Form Authentication in ASP.NET.
- How to use C programing language in Linux as a expert[ZT]
- How To contain multiple fileds in the querystrig, DataNavigateUrlFormatString=xxx.asp?ID={0}&Name={1}
- how_to_use_ant_query_data_and_mail
- How to use next and last in Perl
- How To Use ADO.NET to Retrieve and Modify Records in an Excel Workbook With Visual Basic .NET(利用Ado.net导出到Excel)
- How To Use the ODBC .NET Managed Provider in Visual C# .NET and Connection Strings
- How To Use WordBasic Functions in an MFC Automation Client for Word 97, Word 2000, Word 2002, or Word 2003