Evgenii Legotckoi
Қар. 5, 2015, 2:26 Т.Қ.

QML - 011-сабақ. Деректерді QSqlQueryModel-тен Qml TableView-ге беру

Для представления таблиц баз данных в 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 не будет найдена при компиляции проекта.

  1. TEMPLATE = app
  2.  
  3. QT += qml quick widgets sql
  4.  
  5. SOURCES += main.cpp \
  6. database.cpp \
  7. model.cpp
  8.  
  9. RESOURCES += qml.qrc
  10.  
  11. # Additional import path used to resolve QML modules in Qt Creator's code model
  12. QML_IMPORT_PATH =
  13.  
  14. # Default rules for deployment.
  15. include(deployment.pri)
  16.  
  17. HEADERS += \
  18. database.h \
  19. model.h

database.h

Заголовочный файл класса-обёртки для инициализации подключения к базе данных и её создания в случае, если база данных отсутствует. Данный вспомогательный класс фигурировал в ряде более ранних уроков. Например, при работе QSqlTableModel или QSqlRelationalTableModel . Поэтому не буду заострять внимание на нём, а лишь приведу код. И отмечу, что с помощью этого класса создаётся или открывается (если уже создана) база данных в которую при каждом открытии помещается четыре строки. А каждая строка состоит из четырёх колонок: даты ("date"), времени ("time"), псевдослучайного числа ("random") и сообщения о данном числе ("message").

ВНИМАНИЕ!!! - файл базы данных создается в папке C:/example , поэтому или поправьте метод DataBase::connectToDataBase() или создайте папку example на диске C .

  1. #ifndef DATABASE_H
  2. #define DATABASE_H
  3.  
  4. #include <QObject>
  5. #include <QSql>
  6. #include <QSqlQuery>
  7. #include <QSqlError>
  8. #include <QSqlDatabase>
  9. #include <QFile>
  10. #include <QDate>
  11. #include <QDebug>
  12.  
  13. /* Директивы имен таблицы, полей таблицы и базы данных */
  14. #define DATABASE_HOSTNAME "ExampleDataBase"
  15. #define DATABASE_NAME "DataBase.db"
  16.  
  17. #define TABLE "TableExample"
  18. #define TABLE_DATE "date"
  19. #define TABLE_TIME "time"
  20. #define TABLE_MESSAGE "message"
  21. #define TABLE_RANDOM "random"
  22.  
  23. class DataBase : public QObject
  24. {
  25. Q_OBJECT
  26. public:
  27. explicit DataBase(QObject *parent = 0);
  28. ~DataBase();
  29. /* Методы для непосредственной работы с классом
  30. * Подключение к базе данных и вставка записей в таблицу
  31. * */
  32. void connectToDataBase();
  33. bool inserIntoTable(const QVariantList &data);
  34.  
  35. private:
  36. // Сам объект базы данных, с которым будет производиться работа
  37. QSqlDatabase db;
  38.  
  39. private:
  40. /* Внутренние методы для работы с базой данных
  41. * */
  42. bool openDataBase();
  43. bool restoreDataBase();
  44. void closeDataBase();
  45. bool createTable();
  46. };
  47.  
  48. #endif // DATABASE_H

database.cpp

  1. #include "database.h"
  2.  
  3. DataBase::DataBase(QObject *parent) : QObject(parent)
  4. {
  5. // Подключаемся к базе данных
  6. this->connectToDataBase();
  7. /* После чего производим наполнение таблицы базы данных
  8. * контентом, который будет отображаться в TableView
  9. * */
  10. for(int i = 0; i < 4; i++){
  11. QVariantList data;
  12. int random = qrand(); // Получаем случайные целые числа для вставки а базу данных
  13. data.append(QDate::currentDate()); // Получаем текущую дату для вставки в БД
  14. data.append(QTime::currentTime()); // Получаем текущее время для вставки в БД
  15. // Подготавливаем полученное случайное число для вставки в БД
  16. data.append(random);
  17. // Подготавливаем сообщение для вставки в базу данных
  18. data.append("Получено сообщение от " + QString::number(random));
  19. // Вставляем данные в БД
  20. inserIntoTable(data);
  21. }
  22. }
  23.  
  24. DataBase::~DataBase()
  25. {
  26.  
  27. }
  28.  
  29. /* Методы для подключения к базе данных
  30. * */
  31. void DataBase::connectToDataBase()
  32. {
  33. /* Перед подключением к базе данных производим проверку на её существование.
  34. * В зависимости от результата производим открытие базы данных или её восстановление
  35. * */
  36. if(!QFile("C:/example/" DATABASE_NAME).exists()){
  37. this->restoreDataBase();
  38. } else {
  39. this->openDataBase();
  40. }
  41. }
  42.  
  43. /* Методы восстановления базы данных
  44. * */
  45. bool DataBase::restoreDataBase()
  46. {
  47. if(this->openDataBase()){
  48. if(!this->createTable()){
  49. return false;
  50. } else {
  51. return true;
  52. }
  53. } else {
  54. qDebug() << "Не удалось восстановить базу данных";
  55. return false;
  56. }
  57. return false;
  58. }
  59.  
  60. /* Метод для открытия базы данных
  61. * */
  62. bool DataBase::openDataBase()
  63. {
  64. /* База данных открывается по заданному пути
  65. * и имени базы данных, если она существует
  66. * */
  67. db = QSqlDatabase::addDatabase("QSQLITE");
  68. db.setHostName(DATABASE_HOSTNAME);
  69. db.setDatabaseName("C:/example/" DATABASE_NAME);
  70. if(db.open()){
  71. return true;
  72. } else {
  73. return false;
  74. }
  75. }
  76.  
  77. /* Методы закрытия базы данных
  78. * */
  79. void DataBase::closeDataBase()
  80. {
  81. db.close();
  82. }
  83.  
  84. /* Метод для создания таблицы в базе данных
  85. * */
  86. bool DataBase::createTable()
  87. {
  88. /* В данном случае используется формирование сырого SQL-запроса
  89. * с последующим его выполнением.
  90. * */
  91. QSqlQuery query;
  92. if(!query.exec( "CREATE TABLE " TABLE " ("
  93. "id INTEGER PRIMARY KEY AUTOINCREMENT, "
  94. TABLE_DATE " DATE NOT NULL,"
  95. TABLE_TIME " TIME NOT NULL,"
  96. TABLE_RANDOM " INTEGER NOT NULL,"
  97. TABLE_MESSAGE " VARCHAR(255) NOT NULL"
  98. " )"
  99. )){
  100. qDebug() << "DataBase: error of create " << TABLE;
  101. qDebug() << query.lastError().text();
  102. return false;
  103. } else {
  104. return true;
  105. }
  106. return false;
  107. }
  108.  
  109. /* Метод для вставки записи в базу данных
  110. * */
  111. bool DataBase::inserIntoTable(const QVariantList &data)
  112. {
  113. /* Запрос SQL формируется из QVariantList,
  114. * в который передаются данные для вставки в таблицу.
  115. * */
  116. QSqlQuery query;
  117. /* В начале SQL запрос формируется с ключами,
  118. * которые потом связываются методом bindValue
  119. * для подстановки данных из QVariantList
  120. * */
  121. query.prepare("INSERT INTO " TABLE " ( " TABLE_DATE ", "
  122. TABLE_TIME ", "
  123. TABLE_RANDOM ", "
  124. TABLE_MESSAGE " ) "
  125. "VALUES (:Date, :Time, :Random, :Message )");
  126. query.bindValue(":Date", data[0].toDate());
  127. query.bindValue(":Time", data[1].toTime());
  128. query.bindValue(":Random", data[2].toInt());
  129. query.bindValue(":Message", data[3].toString());
  130. // После чего выполняется запросом методом exec()
  131. if(!query.exec()){
  132. qDebug() << "error insert into " << TABLE;
  133. qDebug() << query.lastError().text();
  134. return false;
  135. } else {
  136. return true;
  137. }
  138. return false;
  139. }

model.h

А теперь самое интересное. Отнаследуемся от класса QSqlQueryModel и создадим собственный класс модели, который будет возвращать данные в соответствии с определёнными ролями колонок в TableView в Qml слое. То есть переопределяем метод для получения данных - это метод data() , а также метод roleNames() , который возвращает имена ролей в соответствии с которыми будут подставляться данные в TableView, отмечу, что имена должны будут совпадать.

  1. #ifndef MODEL_H
  2. #define MODEL_H
  3.  
  4. #include <QObject>
  5. #include <QSqlQueryModel>
  6.  
  7. class Model : public QSqlQueryModel
  8. {
  9. Q_OBJECT
  10. public:
  11. // Перечисляем все роли, которые будут использоваться в TableView
  12. enum Roles {
  13. DateRole = Qt::UserRole + 1, // дата
  14. TimeRole, // время
  15. RandomRole, // псевдослучаное число
  16. MessageRole // сообщение
  17. };
  18.  
  19. // объявляем конструктор класса
  20. explicit Model(QObject *parent = 0);
  21.  
  22. // Переопределяем метод, который будет возвращать данные
  23. QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
  24.  
  25. protected:
  26. /* хешированная таблица ролей для колонок.
  27. * Метод используется в дебрях базового класса QAbstractItemModel,
  28. * от которого наследован класс QSqlQueryModel
  29. * */
  30. QHash<int, QByteArray> roleNames() const;
  31.  
  32. signals:
  33.  
  34. public slots:
  35. };
  36.  
  37. #endif // MODEL_H

model.cpp

  1. #include "model.h"
  2.  
  3. Model::Model(QObject *parent) :
  4. QSqlQueryModel(parent)
  5. {
  6. // Конструктор будет пустой ;-)
  7. }
  8.  
  9. // Метод для получения данных из модели
  10. QVariant Model::data(const QModelIndex & index, int role) const {
  11.  
  12. // Определяем номер колонки, адрес так сказать, по номеру роли
  13. int columnId = role - Qt::UserRole - 1;
  14. // Создаём индекс с помощью новоиспечённого ID колонки
  15. QModelIndex modelIndex = this->index(index.row(), columnId);
  16.  
  17. /* И с помощью уже метода data() базового класса
  18. * вытаскиваем данные для таблицы из модели
  19. * */
  20. return QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
  21. }
  22.  
  23. // Метод для получения имен ролей через хешированную таблицу.
  24. QHash<int, QByteArray> Model::roleNames() const {
  25. /* То есть сохраняем в хеш-таблицу названия ролей
  26. * по их номеру
  27. * */
  28. QHash<int, QByteArray> roles;
  29. roles[DateRole] = "date";
  30. roles[TimeRole] = "time";
  31. roles[RandomRole] = "random";
  32. roles[MessageRole] = "message";
  33. return roles;
  34. }

main.cpp

А теперь, пользуясь приемами регистрации обращения к C++ объекту в QML слое из урока по сигналам и слотам в QML регистрируем кастомную модель данных в QML слое в качестве свойства, к которому можно обращаться по имени "myModel" из QML слоя. Не забыв, конечно выполнить SQL-запрос для получения данных.

  1. #include <QApplication>
  2. #include <QQmlApplicationEngine>
  3. #include <QQmlContext>
  4.  
  5. #include <database.h>
  6. #include <model.h>
  7.  
  8. int main(int argc, char *argv[])
  9. {
  10. QApplication app(argc, argv);
  11. QQmlApplicationEngine engine;
  12.  
  13. // Инициализируем базу данных
  14. DataBase database;
  15. // Объявляем и инициализируем модель представления данных
  16. Model *model = new Model();
  17. /* Поскольку Мы отнаследовались от QSqlQueryModel, то
  18. * для выборки данных нам необходимо выполнить SQL-запрос,
  19. * в котором мы выберем все необходимы поля из нужной нам таблицы
  20. * */
  21. model->setQuery("SELECT " TABLE_DATE ", " TABLE_TIME ", " TABLE_RANDOM ", " TABLE_MESSAGE
  22. " FROM " TABLE);
  23.  
  24. /* А это уже знакомо из уроков по сигналам и слотам в QML
  25. * Помещаем полученную модель в контекст QML, чтобы была возможность
  26. * обращаться к модели по имени "myModel"
  27. * */
  28. engine.rootContext()->setContextProperty("myModel", model);
  29.  
  30. engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
  31.  
  32. return app.exec();
  33. }

main.qml

И самое простое из всего примера - это установка TableView с колонками, которых распределены роли, по которым будут подставлены данные, а также установить саму модель по зарегистрированному имени "myModel".

  1. import QtQuick 2.5
  2. import QtQuick.Controls 1.4
  3.  
  4. ApplicationWindow {
  5. visible: true
  6. width: 640
  7. height: 480
  8. title: qsTr("Hello World")
  9.  
  10. TableView {
  11. anchors.fill: parent
  12.  
  13. TableViewColumn {
  14. role: "date" // Эти роли совпадают с названиями ролей в C++ модели
  15. title: "Date"
  16. }
  17.  
  18. TableViewColumn {
  19. role: "time" // Эти роли совпадают с названиями ролей в C++ модели
  20. title: "Time"
  21. }
  22.  
  23. TableViewColumn {
  24. role: "random" // Эти роли совпадают с названиями ролей в C++ модели
  25. title: "Random"
  26. }
  27.  
  28. TableViewColumn {
  29. role: "message" // Эти роли совпадают с названиями ролей в C++ модели
  30. title: "Message"
  31. }
  32.  
  33. // Устанавливаем модель в TableView
  34. model: myModel
  35. }
  36. }

Итог

В результате всего выше перечисленного колдунства Вы получите приложение, в окне которого будет TableView с данными выдернутыми из базы данных, как показано на рисунке. Также рекомендую видеоурок по данной статье.

Видеоурок

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

AK
  • Қар. 1, 2020, 3:56 Т.Қ.
  • (өңделген)

Добрый день.
Можно ли как то вставить картинку в TableView? Допустим в бд есть boolean столбец который говорит нам добавлен ли объект в избранное, как можно исходя из данных этого поля отобразить ту или иную иконку в TableView?
Пробовал так хотя бы отобразить иконку в 1 колонке добавив в data()

  1. if ( role==FavRole && index.column() == 0) {
  2. return QIcon("D:/Users/Downloads/ico.ico");
  3. }

Но иконка вставляется текстом

R
  • Маусым 17, 2023, 2:15 Т.Қ.

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз