Для представлення таблиць баз даних у 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
база даних.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()
Но иконка вставляется текстом
Ну что, ты разобрался?