Для представления таблиц баз данных в TableView при разработке с использованием QML можно использовать класс, наследованный от QSqlQueryModel. Для этого необходимо в наследованном классе определить метод, который установит соответствие ролей колонок таблицы к соответствующим колонкам в TableView, определенном в QML, где также указаны роли для каждого объекта TableViewColumn, то есть для каждой колонки. Также необходимо будет переопределить метод QVariant data( ... ) const , который возвращает данные для ячеек таблицы. В данном случае информация будет возвращаться в соответствии с определёнными ролями колонок таблицы.
Структура проекта для работы с TableView
Проект состоит из следующих файлов:
- QmlSqlQueryModel.pro - профайл проекта;
- database.h - заголовочный для создания и инициализации тестовой базы данных;
- database.cpp - файл исходных кодов для создания и инициализации тестовой базы данных;
- model.h - заголовочный файл модели данных;
- model.cpp - файл исходных кодов модели данных;
- main.cpp - основной исходный файл проекта;
- main.qml - qml файл с TableView.
QmlSqlQueryModel.pro
Обязательно подключите модуль SQL в проект в данном файле. Иначе библиотека QSqlQueryModel не будет найдена при компиляции проекта.
- TEMPLATE = app
- QT += qml quick widgets sql
- SOURCES += main.cpp \
- database.cpp \
- model.cpp
- RESOURCES += qml.qrc
- # Additional import path used to resolve QML modules in Qt Creator's code model
- QML_IMPORT_PATH =
- # Default rules for deployment.
- include(deployment.pri)
- HEADERS += \
- database.h \
- model.h
database.h
Заголовочный файл класса-обёртки для инициализации подключения к базе данных и её создания в случае, если база данных отсутствует. Данный вспомогательный класс фигурировал в ряде более ранних уроков. Например, при работе QSqlTableModel или QSqlRelationalTableModel . Поэтому не буду заострять внимание на нём, а лишь приведу код. И отмечу, что с помощью этого класса создаётся или открывается (если уже создана) база данных в которую при каждом открытии помещается четыре строки. А каждая строка состоит из четырёх колонок: даты ("date"), времени ("time"), псевдослучайного числа ("random") и сообщения о данном числе ("message").
ВНИМАНИЕ!!! - файл базы данных создается в папке C:/example , поэтому или поправьте метод DataBase::connectToDataBase() или создайте папку example на диске C .
- #ifndef DATABASE_H
- #define DATABASE_H
- #include <QObject>
- #include <QSql>
- #include <QSqlQuery>
- #include <QSqlError>
- #include <QSqlDatabase>
- #include <QFile>
- #include <QDate>
- #include <QDebug>
- /* Директивы имен таблицы, полей таблицы и базы данных */
- #define DATABASE_HOSTNAME "ExampleDataBase"
- #define DATABASE_NAME "DataBase.db"
- #define TABLE "TableExample"
- #define TABLE_DATE "date"
- #define TABLE_TIME "time"
- #define TABLE_MESSAGE "message"
- #define TABLE_RANDOM "random"
- class DataBase : public QObject
- {
- Q_OBJECT
- public:
- explicit DataBase(QObject *parent = 0);
- ~DataBase();
- /* Методы для непосредственной работы с классом
- * Подключение к базе данных и вставка записей в таблицу
- * */
- void connectToDataBase();
- bool inserIntoTable(const QVariantList &data);
- private:
- // Сам объект базы данных, с которым будет производиться работа
- QSqlDatabase db;
- private:
- /* Внутренние методы для работы с базой данных
- * */
- bool openDataBase();
- bool restoreDataBase();
- void closeDataBase();
- bool createTable();
- };
- #endif // DATABASE_H
database.cpp
- #include "database.h"
- DataBase::DataBase(QObject *parent) : QObject(parent)
- {
- // Подключаемся к базе данных
- this->connectToDataBase();
- /* После чего производим наполнение таблицы базы данных
- * контентом, который будет отображаться в TableView
- * */
- for(int i = 0; i < 4; i++){
- QVariantList data;
- int random = qrand(); // Получаем случайные целые числа для вставки а базу данных
- data.append(QDate::currentDate()); // Получаем текущую дату для вставки в БД
- data.append(QTime::currentTime()); // Получаем текущее время для вставки в БД
- // Подготавливаем полученное случайное число для вставки в БД
- data.append(random);
- // Подготавливаем сообщение для вставки в базу данных
- data.append("Получено сообщение от " + QString::number(random));
- // Вставляем данные в БД
- inserIntoTable(data);
- }
- }
- DataBase::~DataBase()
- {
- }
- /* Методы для подключения к базе данных
- * */
- void DataBase::connectToDataBase()
- {
- /* Перед подключением к базе данных производим проверку на её существование.
- * В зависимости от результата производим открытие базы данных или её восстановление
- * */
- if(!QFile("C:/example/" DATABASE_NAME).exists()){
- this->restoreDataBase();
- } else {
- this->openDataBase();
- }
- }
- /* Методы восстановления базы данных
- * */
- bool DataBase::restoreDataBase()
- {
- if(this->openDataBase()){
- if(!this->createTable()){
- return false;
- } else {
- return true;
- }
- } else {
- qDebug() << "Не удалось восстановить базу данных";
- return false;
- }
- return false;
- }
- /* Метод для открытия базы данных
- * */
- bool DataBase::openDataBase()
- {
- /* База данных открывается по заданному пути
- * и имени базы данных, если она существует
- * */
- db = QSqlDatabase::addDatabase("QSQLITE");
- db.setHostName(DATABASE_HOSTNAME);
- db.setDatabaseName("C:/example/" DATABASE_NAME);
- if(db.open()){
- return true;
- } else {
- return false;
- }
- }
- /* Методы закрытия базы данных
- * */
- void DataBase::closeDataBase()
- {
- db.close();
- }
- /* Метод для создания таблицы в базе данных
- * */
- bool DataBase::createTable()
- {
- /* В данном случае используется формирование сырого SQL-запроса
- * с последующим его выполнением.
- * */
- QSqlQuery query;
- if(!query.exec( "CREATE TABLE " TABLE " ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- TABLE_DATE " DATE NOT NULL,"
- TABLE_TIME " TIME NOT NULL,"
- TABLE_RANDOM " INTEGER NOT NULL,"
- TABLE_MESSAGE " VARCHAR(255) NOT NULL"
- " )"
- )){
- qDebug() << "DataBase: error of create " << TABLE;
- qDebug() << query.lastError().text();
- return false;
- } else {
- return true;
- }
- return false;
- }
- /* Метод для вставки записи в базу данных
- * */
- bool DataBase::inserIntoTable(const QVariantList &data)
- {
- /* Запрос SQL формируется из QVariantList,
- * в который передаются данные для вставки в таблицу.
- * */
- QSqlQuery query;
- /* В начале SQL запрос формируется с ключами,
- * которые потом связываются методом bindValue
- * для подстановки данных из QVariantList
- * */
- query.prepare("INSERT INTO " TABLE " ( " TABLE_DATE ", "
- TABLE_TIME ", "
- TABLE_RANDOM ", "
- TABLE_MESSAGE " ) "
- "VALUES (:Date, :Time, :Random, :Message )");
- query.bindValue(":Date", data[0].toDate());
- query.bindValue(":Time", data[1].toTime());
- query.bindValue(":Random", data[2].toInt());
- query.bindValue(":Message", data[3].toString());
- // После чего выполняется запросом методом exec()
- if(!query.exec()){
- qDebug() << "error insert into " << TABLE;
- qDebug() << query.lastError().text();
- return false;
- } else {
- return true;
- }
- return false;
- }
model.h
А теперь самое интересное. Отнаследуемся от класса QSqlQueryModel и создадим собственный класс модели, который будет возвращать данные в соответствии с определёнными ролями колонок в TableView в Qml слое. То есть переопределяем метод для получения данных - это метод data() , а также метод roleNames() , который возвращает имена ролей в соответствии с которыми будут подставляться данные в TableView, отмечу, что имена должны будут совпадать.
- #ifndef MODEL_H
- #define MODEL_H
- #include <QObject>
- #include <QSqlQueryModel>
- class Model : public QSqlQueryModel
- {
- Q_OBJECT
- public:
- // Перечисляем все роли, которые будут использоваться в TableView
- enum Roles {
- DateRole = Qt::UserRole + 1, // дата
- TimeRole, // время
- RandomRole, // псевдослучаное число
- MessageRole // сообщение
- };
- // объявляем конструктор класса
- explicit Model(QObject *parent = 0);
- // Переопределяем метод, который будет возвращать данные
- QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
- protected:
- /* хешированная таблица ролей для колонок.
- * Метод используется в дебрях базового класса QAbstractItemModel,
- * от которого наследован класс QSqlQueryModel
- * */
- QHash<int, QByteArray> roleNames() const;
- signals:
- public slots:
- };
- #endif // MODEL_H
model.cpp
- #include "model.h"
- Model::Model(QObject *parent) :
- QSqlQueryModel(parent)
- {
- // Конструктор будет пустой ;-)
- }
- // Метод для получения данных из модели
- QVariant Model::data(const QModelIndex & index, int role) const {
- // Определяем номер колонки, адрес так сказать, по номеру роли
- int columnId = role - Qt::UserRole - 1;
- // Создаём индекс с помощью новоиспечённого ID колонки
- QModelIndex modelIndex = this->index(index.row(), columnId);
- /* И с помощью уже метода data() базового класса
- * вытаскиваем данные для таблицы из модели
- * */
- return QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
- }
- // Метод для получения имен ролей через хешированную таблицу.
- QHash<int, QByteArray> Model::roleNames() const {
- /* То есть сохраняем в хеш-таблицу названия ролей
- * по их номеру
- * */
- QHash<int, QByteArray> roles;
- roles[DateRole] = "date";
- roles[TimeRole] = "time";
- roles[RandomRole] = "random";
- roles[MessageRole] = "message";
- return roles;
- }
main.cpp
А теперь, пользуясь приемами регистрации обращения к C++ объекту в QML слое из урока по сигналам и слотам в QML регистрируем кастомную модель данных в QML слое в качестве свойства, к которому можно обращаться по имени "myModel" из QML слоя. Не забыв, конечно выполнить SQL-запрос для получения данных.
- #include <QApplication>
- #include <QQmlApplicationEngine>
- #include <QQmlContext>
- #include <database.h>
- #include <model.h>
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- QQmlApplicationEngine engine;
- // Инициализируем базу данных
- DataBase database;
- // Объявляем и инициализируем модель представления данных
- Model *model = new Model();
- /* Поскольку Мы отнаследовались от QSqlQueryModel, то
- * для выборки данных нам необходимо выполнить SQL-запрос,
- * в котором мы выберем все необходимы поля из нужной нам таблицы
- * */
- model->setQuery("SELECT " TABLE_DATE ", " TABLE_TIME ", " TABLE_RANDOM ", " TABLE_MESSAGE
- " FROM " TABLE);
- /* А это уже знакомо из уроков по сигналам и слотам в QML
- * Помещаем полученную модель в контекст QML, чтобы была возможность
- * обращаться к модели по имени "myModel"
- * */
- engine.rootContext()->setContextProperty("myModel", model);
- engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
- return app.exec();
- }
main.qml
И самое простое из всего примера - это установка TableView с колонками, которых распределены роли, по которым будут подставлены данные, а также установить саму модель по зарегистрированному имени "myModel".
- import QtQuick 2.5
- import QtQuick.Controls 1.4
- ApplicationWindow {
- visible: true
- width: 640
- height: 480
- title: qsTr("Hello World")
- TableView {
- anchors.fill: parent
- TableViewColumn {
- role: "date" // Эти роли совпадают с названиями ролей в C++ модели
- title: "Date"
- }
- TableViewColumn {
- role: "time" // Эти роли совпадают с названиями ролей в C++ модели
- title: "Time"
- }
- TableViewColumn {
- role: "random" // Эти роли совпадают с названиями ролей в C++ модели
- title: "Random"
- }
- TableViewColumn {
- role: "message" // Эти роли совпадают с названиями ролей в C++ модели
- title: "Message"
- }
- // Устанавливаем модель в TableView
- model: myModel
- }
- }
Итог
В результате всего выше перечисленного колдунства Вы получите приложение, в окне которого будет TableView с данными выдернутыми из базы данных, как показано на рисунке. Также рекомендую видеоурок по данной статье.
Добрый день.
Можно ли как то вставить картинку в TableView? Допустим в бд есть boolean столбец который говорит нам добавлен ли объект в избранное, как можно исходя из данных этого поля отобразить ту или иную иконку в TableView?
Пробовал так хотя бы отобразить иконку в 1 колонке добавив в data()
Но иконка вставляется текстом

Ну что, ты разобрался?