Evgenii Legotckoi
14 августа 2015 г. 23:44

Qt/C++ - Урок 004. QSqlTableModel или Как представить таблицу из БД в Qt?

Для того, чтобы представить информацию, содержащуюся в таблице базы данных, во фреймворке Qt используется несколько классов:

  • QSqlQueryModel - модель, которая формирует таблицу путем задания сырого SQL-запроса. Может быть полезна при формировании особо изощренных фильтров и компиляции информации из различных таблиц базы данных. О ней подробнее в следующих уроках.
  • QSqlTableModel - предмет нашей беседы в данной статье. Модель, которая формирует таблицу по имени той таблицы, которая существует в базе данных. Из минусов можно отметить отсутствие методов подключения связей c другими таблицами, чтобы подставлять значения в поля из других таблиц по ID.
  • QSqlRelationalTableModel - класс, который позволяет формировать таблицу со связями из других таблиц, подменяя значения таблицы, которую представляет данная модель, по ID записей, содержащихся в других таблицах.

Для комфортной работы с информацией, которая помещена в базу данных применяется дополнительный класс, который частично представляет собой шаблон проектирования "Фасад" .

Программный код был написан в QtCreator 3.3.1 на основе Qt 5.4.1.

Структура проекта для QSqlTableModel

Проект создается как Приложение Qt Widgets, в котором создаются следующие файлы:

  • DataBase.pro - профайл;
  • mainwindow.h - заголовочный файл основного окна приложения;
  • mainwindow.cpp - исходный код окна;
  • main.cpp - основной исходный файл, с которого стартует приложение;
  • mainwindow.ui - формочка основного окна приложения;
  • database.h - заголовочный файл вспомогательного класса, применяющегося для работы с информацией, которая помещена в базу данных;
  • database.cpp - исходный файл вспомогательного класса, применяющегося для работы с информацией, которая помещена в базу данных;

Примечание. Большую часть интерфейса создаю в дизайнере, чтобы не загромождать логику основного кода лишней информацией. По сути это лишь дело вкуса и привычки.

mainwindow.ui

Формочка для QSqlTableModel Создаем формочку для тестового приложения, в котором будет из графического интерфейса использоваться объект QTableView под названием tableView .

DataBase.pro

В Профайл проекта необходимо добавить директиву, которая объявляет об использовании библиотек SQL.

  1. #-------------------------------------------------
  2. #
  3. # Project created by QtCreator 2015-08-10T16:08:24
  4. #
  5. #-------------------------------------------------
  6.  
  7. QT += core
  8. QT += gui
  9. QT += sql
  10.  
  11. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  12.  
  13. TARGET = DataBase
  14. TEMPLATE = app
  15.  
  16.  
  17. SOURCES += main.cpp\
  18. mainwindow.cpp \
  19. database.cpp
  20.  
  21. HEADERS += mainwindow.h \
  22. database.h
  23.  
  24. FORMS += mainwindow.ui

main.cpp

Файл используется в проекте, будучи созданным по умолчанию.

  1. #include "mainwindow.h"
  2. #include <QApplication>
  3.  
  4. int main(int argc, char *argv[])
  5. {
  6. QApplication a(argc, argv);
  7. MainWindow w;
  8. w.show();
  9.  
  10. return a.exec();
  11. }

mainwindow.h

В данном заголовочном файле помещается объявление объекта QSqlTableModel и DataBase , вспомогательного класса, применяющегося для работы с информацией, которая помещена в базу данных. Помимо них объявлены методы для инициализации внешнего вида и модели QSqlTableModel нашего приложения.

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3.  
  4. #include <QMainWindow>
  5. #include <QSqlTableModel>
  6. /* Подключаем заголовочный файл для работы с информацией, которая помещена в базу данных */
  7. #include "database.h"
  8.  
  9. namespace Ui {
  10. class MainWindow;
  11. }
  12.  
  13. class MainWindow : public QMainWindow
  14. {
  15. Q_OBJECT
  16.  
  17. public:
  18. explicit MainWindow(QWidget *parent = 0);
  19. ~MainWindow();
  20.  
  21. private:
  22. Ui::MainWindow *ui;
  23. /* В проекте используются объекты для взаимодействия с информацией в базе данных
  24. * и моделью представления таблицы базы данных
  25. * */
  26. DataBase *db;
  27. QSqlTableModel *model;
  28.  
  29. private:
  30. /* Также присутствуют два метода, которые формируют модель
  31. * и внешний вид TableView
  32. * */
  33. void setupModel(const QString &tableName, const QStringList &headers);
  34. void createUI();
  35. };
  36.  
  37. #endif // MAINWINDOW_H

mainwindow.cpp

Исходный файл, в котором происходит всё основное действо по взаимодействию с моделью представления данных.

  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3.  
  4. MainWindow::MainWindow(QWidget *parent) :
  5. QMainWindow(parent),
  6. ui(new Ui::MainWindow)
  7. {
  8. ui->setupUi(this);
  9.  
  10. /* Первым делом необходимо создать объект, который будет использоваться для работы с данными нашей БД
  11. * и инициализировать подключение к базе данных
  12. * */
  13. db = new DataBase();
  14. db->connectToDataBase();
  15.  
  16. /* После чего производим наполнение таблицы базы данных
  17. * контентом, который будет отображаться в TableView
  18. * */
  19. for(int i = 0; i < 4; i++){
  20. QVariantList data;
  21. int random = qrand(); // Получаем случайные целые числа для вставки а базу данных
  22. data.append(QDate::currentDate()); // Получаем текущую дату для вставки в БД
  23. data.append(QTime::currentTime()); // Получаем текущее время для вставки в БД
  24. // Подготавливаем полученное случайное число для вставки в БД
  25. data.append(random);
  26. // Подготавливаем сообщение для вставки в базу данных
  27. data.append("Получено сообщение от " + QString::number(random));
  28. // Вставляем данные в БД
  29. db->inserIntoTable(data);
  30. }
  31.  
  32. /* Инициализируем модель для представления данных
  33. * с заданием названий колонок
  34. * */
  35. this->setupModel(TABLE,
  36. QStringList() << trUtf8("id")
  37. << trUtf8("Дата")
  38. << trUtf8("Время")
  39. << trUtf8("Рандомное число")
  40. << trUtf8("Сообщение")
  41. );
  42.  
  43. /* Инициализируем внешний вид таблицы с данными
  44. * */
  45. this->createUI();
  46. }
  47.  
  48. MainWindow::~MainWindow()
  49. {
  50. delete ui;
  51. }
  52.  
  53. /* Метод для инициализации модеи представления данных
  54. * */
  55. void MainWindow::setupModel(const QString &tableName, const QStringList &headers)
  56. {
  57. /* Производим инициализацию модели представления данных
  58. * с установкой имени таблицы в базе данных, по которому
  59. * будет производится обращение в таблице
  60. * */
  61. model = new QSqlTableModel(this);
  62. model->setTable(tableName);
  63.  
  64. /* Устанавливаем названия колонок в таблице с сортировкой данных
  65. * */
  66. for(int i = 0, j = 0; i < model->columnCount(); i++, j++){
  67. model->setHeaderData(i,Qt::Horizontal,headers[j]);
  68. }
  69. // Устанавливаем сортировку по возрастанию данных по нулевой колонке
  70. model->setSort(0,Qt::AscendingOrder);
  71. }
  72.  
  73. void MainWindow::createUI()
  74. {
  75. ui->tableView->setModel(model); // Устанавливаем модель на TableView
  76. ui->tableView->setColumnHidden(0, true); // Скрываем колонку с id записей
  77. // Разрешаем выделение строк
  78. ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
  79. // Устанавливаем режим выделения лишь одно строки в таблице
  80. ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
  81. // Устанавливаем размер колонок по содержимому
  82. ui->tableView->resizeColumnsToContents();
  83. ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
  84. ui->tableView->horizontalHeader()->setStretchLastSection(true);
  85.  
  86. model->select(); // Делаем выборку данных из таблицы
  87. }

database.h

Чтобы не оставлять в полной тьме вопрос по взаимодействию с базой данных, также привожу листинги данного класса с комментариями. Работа производится с базой данных SQLite, но принцип работы с сетевыми базами данных будет аналогичен, за исключением сетевого подключения и нюансов работы с каждой конкретной базой данных.

В заголовочном файле класса DataBase необходимо указать директивы названий таблицы и колонок таблицы для удобства дальнейшей работы. А также методы, которые используются для взаимодействия с базой данных, а также предоставления интерфейсов для этого взаимодействия с более высокоуровневыми прослойками приложения.

  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

Исходный файл вспомогательного класса, применяющегося для работы с информацией, которая помещена в базу данных. В данном случае формирование SQL запросов прячется по максимуму в данный класс, чтобы уменьшить количество связей в программном коде. Подобная практика в самом начале может помочь привить новичку умение сразу писать код, в котором различные классы по максимум обособлены друг от друга, что и является одним из аспектов ООП.

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

Итог

В результате должна получиться табличка следующего вида с данными, которые были подготовлены и вставлены в конструкторе главного окна приложения.

Внешний вид приложения с QSqlTableModel

Вам это нравится? Поделитесь в социальных сетях!

И
  • 14 апреля 2017 г. 20:51

Здравствуйте, а, скажите, сам объект QSqlTableModel предоставляет доступ к данным, которые уже есть в таблице? Например, получить в какую - то переменную ранее записанное рандомное число из строки с индексом n?Или, это только возможно запросом

И
  • 14 апреля 2017 г. 20:54

Метод setData(строка, столбец, значение) есть, а, метода, например, типа, getData(строка, столбец), не нашел

И
  • 14 апреля 2017 г. 21:10

Разобрался QSqlRecord rec = model(номер строки) - получаем строку int num = rec.value("TABLE_RANDOM"); - получаем поле

Evgenii Legotckoi
  • 14 апреля 2017 г. 21:19

Всё гораздо проще, метод, который Вы искали называется не getData() , а просто data() . Для получения данных нужно дернуть QModelIndex из модели. Выглядеть это будет так:

model->data(model->index(0, 2)); 
// 0 - номер строки
// 2 - номер колонки

Метод вернёт QVariant , который будет содержать данные.

z
  • 7 мая 2017 г. 20:43

А у меня выхлоп: Не удалось восстановить базу данных QSqlQuery::prepare: database not open error insert into TableExample "No query Unable to fetch row" QSqlQuery::prepare: database not open error insert into TableExample "No query Unable to fetch row" QSqlQuery::prepare: database not open error insert into TableExample "No query Unable to fetch row" QSqlQuery::prepare: database not open error insert into TableExample "No query Unable to fetch row" QSqlQuery::prepare: database not open error insert into TableExample "No query Unable to fetch row" QSqlDatabasePrivate::database: unable to open database: "out of memory Error opening database"

Evgenii Legotckoi
  • 7 мая 2017 г. 21:31

В методах connectToDataBase и openToDataBase пропишите свой путь к базе данных.

z
  • 7 мая 2017 г. 22:23

Тоесть надо создать пустую базу sqlite сторонним ПО?

Evgenii Legotckoi
  • 7 мая 2017 г. 22:25

Нет. нужно указать корректный пути к базе данных. Если вы скопипастили код, то скорее всего у вас нет директории example на диске C, поэтому и не фурычит.

v
  • 27 апреля 2018 г. 4:20

Здравствуйте, очень понравился Ваш урок. Сначала решил взять идею - не получилось, причем ошибки странные. После этого решил взять Ваш код и выяснилось, что ошибки остаются теми же. Компилятор ругается на то, что вроде как конструктор и деструктор класса DataBase должны быть виртуальными...Плохое решение проблемы, но все же отчасти ее решение - это убрать макрос Q_Object в заголовочном файле DataBase. При таком решении проблемы выскакивает ошибка " ASSERT: "!isEmpty()" in file ....." и программа сворачивается. Пожалуйста, подскажите в чем загвоздка, почему так и как это все исправить? Есть предположение, что это связано с настройкой компилятора, но...не знаю.

v
  • 27 апреля 2018 г. 4:35

К посту выше...Проблема "виртуальных" конструктора и деструктора решается с помощью перезапуска qmake (его вообще нужно всегда перезапускать, если добавляешь макрос Q_Object в свой класс). Но вторая проблема, к сожалению осталась актуальной((  "ASSERT: "!isEmpty()" in file C:/Users/qt/work/qt/qtbase/src/corelib/tools/qlist.h, line 345 "

Evgenii Legotckoi
  • 27 апреля 2018 г. 13:39

Добрый день! В методе connectToDataBase вы прописали свой путь к базе данных?

v
  • 27 апреля 2018 г. 13:57

Да

Evgenii Legotckoi
  • 27 апреля 2018 г. 14:03

Сейчас сразу и не припомню, было ли нечто такое, может в новых версиях Qt что-то поменяли, что генерирует ошибку. После работы гляну, какая там может быть проблема.

v
  • 27 апреля 2018 г. 14:06

Хорошо, спасибо большое! Очень жду Вашего ответа. Я тоже пока попробую разобраться и может реализовать как-нибудь по-другому.

v
  • 27 апреля 2018 г. 19:31

У меня все заработало. Не могу точно сказать в чем была причина, есть только догадки. Но программа заработала только после того, как я удалил базу данных с таким же названием, которая была создана мною вручную. Наверное, это мешало корректной работе программы, но не совсем ясно почему...ведь мы всего лишь обращаемся к этой БД с запросами и все.

Evgenii Legotckoi
  • 27 апреля 2018 г. 19:33

Скорее всего дело в метаинформации, которой не было при создании файла вручную. При подключении некорректный файл крашил программу...

v
  • 27 апреля 2018 г. 19:36

Да, спасибо Вам большое! У Вас очень интересные уроки!!!

Evgenii Legotckoi
  • 27 апреля 2018 г. 19:38

Спасибо за отзыв. Будут вопросы не по статьям, то не стесняйтесь задавать их на форуме сайта .

B
  • 8 октября 2018 г. 14:06

DataBase is unknown type. Подскажите, в чем проблема, вроде все заголовочные подключаю

B
  • 8 октября 2018 г. 14:07

Все понял

Evgenii Legotckoi
  • 8 октября 2018 г. 14:07

ММм.. хорошо, А что там не так было?

B
  • 8 октября 2018 г. 16:41

Я не подключил header класса, поэтому он не знал тип такой. Подскажите пожалуйста

Я qDebug()`ом вызываю значения, которые подаю в базу данных, как я понимаю, база ругается на QDate и QTime


QDate("2018-10-08")

QTime("13:37:04.454")

26500

"Получено сообщение от 26500"

error insert into TableExample

" Parameter count mismatch"

Evgenii Legotckoi
  • 8 октября 2018 г. 16:49

Наверное у вас базад данных не создалась, поправьте путь к место, где должна создаться база данных вот в этом методе

  1. bool DataBase::openDataBase()
  2. {
  3. /* База данных открывается по заданному пути
  4. * и имени базы данных, если она существует
  5. * */
  6. db = QSqlDatabase::addDatabase("QSQLITE");
  7. db.setHostName(DATABASE_HOSTNAME);
  8. db.setDatabaseName("C:/example/" DATABASE_NAME);
  9. if(db.open()){
  10. return true;
  11. } else {
  12. return false;
  13. }
  14. }


B
  • 8 октября 2018 г. 20:21
  1. bool DataBase::openDataBase()
  2. {
  3. db = QSqlDatabase::addDatabase("QSQLITE");
  4.  
  5. db.setHostName(DATABASE_HOSTNAME);
  6. db.setDatabaseName("C:/Users/esmit/Documents/Qt/DataBase/" DATABASE_NAME);
  7.  
  8. if(db.open())
  9. return true;
  10. else
  11. return false;
  12. }


  1.  
B
  • 8 октября 2018 г. 20:27

В отладчике возвращает true, проблема не в этом

Evgenii Legotckoi
  • 8 октября 2018 г. 20:30

Возможно, что пока вы повторяли работу кода из данной статьи, была создана таблица, но с другим количествов столбцов, в результату строка не добавляется из-за различий в запросе и самой таблице. Попробуйте удались базу данных, сконтролируйте, чтобы столбцы соответсвовали тому, что вы пытаетесь добавить в таблицу.

IscanderChe
  • 15 января 2019 г. 20:14

Спасибо за урок!
Вопрос: что нужно сделать, чтобы в tableView показывалось, например, 12:56, а не 12:56:34.554?

Evgenii Legotckoi
  • 15 января 2019 г. 20:17

Наследоваться от QSqlTableModel и переопределить метод data для Qt::DisplayRole. Там сделать необходимые проебразования формата.

И потом уже использовать переопределённую модель вместо QSqlTableModel

IscanderChe
  • 16 января 2019 г. 13:43

Сделал вот так. В tableView ничего нет, кроме заголовка.

  1. QVariant MySqlTableModel::data(const QModelIndex &index, int role) const
  2. {
  3. if (role == Qt::DisplayRole)
  4. {
  5. QTime time = this->data(index, Qt::DisplayRole).toTime();
  6. QString str = time.toString("hh:mm:ss");
  7. return str;
  8. }
  9. else
  10. return QVariant();
  11. }
Evgenii Legotckoi
  • 16 января 2019 г. 13:51
  • (ред.)

потому, что нужно сохранять информацию для всех остальных ролей и столбцов через вызов переопределённого метода. Да к тому же вы ещё и зациклили вызов метода data.

  1. QVariant MySqlTableModel::data(const QModelIndex &index, int role) const
  2. {
  3. if (role == Qt::DisplayRole)
  4. {
  5. QTime time = QSqlTableModel::data(index, Qt::DisplayRole).toTime();
  6. QString str = time.toString("hh:mm:ss");
  7. return str;
  8. }
  9.  
  10. return QSqlTableModel::data(index, role);
  11. }
IscanderChe
  • 16 января 2019 г. 14:02

Всё равно пусто, хотя строка с данными в базу добавляется.

IscanderChe
  • 16 января 2019 г. 14:06

Заработало. Забыл model->select(); вписать.

IscanderChe
  • 16 января 2019 г. 14:06

Спасибо!

IscanderChe
  • 22 января 2019 г. 17:11
  • (ред.)

Ещё небольшой вопрос.
Я добился, чтобы в tableView в колонке flag показывался чекбокс (через флаг Qt::ItemIsUserCheckable) и управлял содержимым базы . Как теперь убрать цифру из поля, чтобы остался только чекбокс?
flag.JPG flag.JPG

Evgenii Legotckoi
  • 22 января 2019 г. 17:50

Переопределить метод data для той колонки и роли Qt::DisplayRole, чтобы в том случае возвращался QVariant() я так думаю...
Но возможно, что у вас там будут нюансы, если вы туда чекбокс запихали

IscanderChe
  • 22 января 2019 г. 18:09

Получилось приемлемо. Спасибо!
Нюанс только в том, что поле рядом с чекбоксом не пропадает, оно просто пустое, что видно при выделении ячейки. Но этого достаточно.

Evgenii Legotckoi
  • 22 января 2019 г. 18:15
  • (ред.)

Если будет не приемлемо потом, то тогда через кастомный Item Delegate нужно будет перерисовать ячейки в той колонке.

IscanderChe
  • 22 января 2019 г. 19:13

Не проще тогда использовать сразу кастомный делегат с чекбоксом? Я попробовал, но там засада в том, что чекбокс показывается только при щелчке на ячейку, а дефолтно показывается значение. Как эту засаду обойти, я не смог придумать, плохо ещё ориентируюсь в моделях.

Evgenii Legotckoi
  • 22 января 2019 г. 19:17
  • (ред.)

Создайте тогда тему здесь на форуме в разделе Qt с выкладками кода и вашими попытками внедрения делегата, позже гляну или может кто-то ещё глянет из опытных пользователей.

a
  • 14 января 2020 г. 13:30

Всем привет. Возник вопрос, можно ли работать с QtSql без сырых sql запросов, как в различный orm, через классы qsqltablemodel, qsqlrelationtablemodel?

Evgenii Legotckoi
  • 14 января 2020 г. 13:33

Добрый день. В Qt нет ORM в QtSql, а классы qsqltablemodel и qsqlrelationtablemodel дают относительно слабый функционал, даже для использования фильтрации потребуется писать кусок SQL запроса. Без сырых запросов не обойдётесь.

a
  • 14 января 2020 г. 13:44

Спасибо. Очень жаль, хотя с другой стороны это дает гораздо больше гибкости.

Evgenii Legotckoi
  • 14 января 2020 г. 13:50
  • (ред.)

Вы заблуждаетесь. Любая нормальная ORM позволяет выполнение сырых SQL запросов. А если хорошо разобраться в работе моделей данных в Qt, то не составит труда использовать ORM вместе с Qt, ту же самую ORM Wt::Dbo. Нет особой гибкости в том, что приходится тратить уйму времени на написание сырых запросов, когда ORM позволяет всё это выполнять значительно быстрее. Я думаю, что со стороны Qt Company - это является недоработкой, что они не попытались сделать свою ORM, ресурсы им сейчас это позволяют. Так что действительно жаль, что этого нет из коробки.

a
  • 14 января 2020 г. 16:29

Спасибо за инфу. Поиск качественной ORM привел меня только к sqlite_orm, но не подходит из-за необходимости полноценной поддержки c++14. Про framework Wt не слышал, спасибо за наводку.

Evgenii Legotckoi
  • 14 января 2020 г. 16:33

Рекомендую Wt, достаточно мощная вещь. Этот фреймворк может использоваться для написания сайтов на C++, либо можно использовать только отдельный компоненты, например только ORM. Но я не знаю, какая требуется минимальная версия стандарта C++ для него. А также он требует boost библиотеку. У нас в проекте используется boost, а также C++17. Поэтому никогда не задумывался о минимальных требованиях к этому фреймворку.

Т1
  • 26 мая 2020 г. 17:00
  • (ред.)

не удается подключиить библеотеку

include "database.h"

выдает ошибку. Можете помочь?

Evgenii Legotckoi
  • 26 мая 2020 г. 17:02

Потому что это файл который нужно создать, а не библиотека.
В статье есть содержание этого файла. Добавляйте в проект. Копируйте содержимое из статьи.

Т1
  • 26 мая 2020 г. 17:22
  • (ред.)

полностью повторил структору проекта. В форму дабавил tableView. Но при запуске получаю форму только с пустым tableView. Можете подсказать в чем пробелма?

Т1
  • 26 мая 2020 г. 17:23

Evgenii Legotckoi
  • 26 мая 2020 г. 17:51

У вас база данных не открылась

Исправьте путь к базе данных на свой корректный в следующих методах

  • void DataBase::connectToDataBase()
  • bool DataBase::openDataBase()
Т1
  • 26 мая 2020 г. 21:38

спасибо, все сработало

Т1
  • 26 мая 2020 г. 21:55
  • (ред.)

Подскажите пожалуйста как изменить данные в базе, тип столбцов и сделать столбцы шире

Evgenii Legotckoi
  • 27 мая 2020 г. 12:51

Напишите метод с SQL запросом, который изменит данные или их тип. Это ALTER методы для изменения типа данных, а также INSERT и UPDATE методы для добавления и обновления данных. Это вы можете найти в документации на SQL. Просто напишите QSqlQuery запросы, как это показано в методе inserIntoTable
Что касается ширины столбцов, то QTableView имеет метод setColumnWidth

VB
  • 16 сентября 2020 г. 15:57
  • (ред.)

Почему-то такой метод для обновления не работает, который можно было бы применить в данном примере. То есть в представлении данные удаляются и обновляются, а в базе данных изменений не происходит:

  1. bool Model::update_in_db(Data *item)
  2. {
  3. QSqlQuery query;
  4. query.setForwardOnly(true);
  5. query.prepare("UPDATE myDB SET \n"
  6. " code_all = :code, \n"
  7. " date = :date, \n"
  8. " person = :person, \n"
  9. "WHERE id = :id; \n"
  10. );
  11.  
  12. query.bindValue(":code", item->Code_all());
  13. query.bindValue(":date", item->Date());
  14. query.bindValue(":person", item->Person());
  15.  
  16. if(query.exec()) {
  17. return true;
  18. } else {
  19. qCritical() << query.lastError().databaseText();
  20. qCritical() << query.lastError().driverText();
  21. qCritical() << query.lastError().nativeErrorCode();
  22.  
  23. return false;
  24. }
  25. }

А также для удаления такой метод не обновляет базу данных SQLite (модель унаследована от QSqlTableModel):

  1. Model::delete_from_db()
  2. {
  3. QSqlQuery query;
  4. query.setForwardOnly(true);
  5. query.prepare("DELETE FROM myDB WHERE id = :ID ;");
  6. query.bindValue(":ID", currentIndex.row());
  7.  
  8. if(!query.exec()){
  9. qCritical() << query.lastError().databaseText().toUtf8().data();
  10. qCritical() << query.lastError().driverText();
  11. qCritical() << query.lastError().nativeErrorCode();
  12. return false;
  13. } else {
  14. return true;
  15. }
  16. return false;
  17. }
d
  • 27 апреля 2022 г. 14:30

Не могу понять как связывается БД и модель. Подскажите, пожалуйста.

IscanderChe
  • 27 апреля 2022 г. 19:43

model = new QSqlTableModel(this);
model->setTable(tableName);

Это строки 61-62 в mainwindow.cpp

d
  • 28 апреля 2022 г. 12:43

IscanderChe. Мы создаем объект класс DataBase. Как этот объект связать с объектом класса QSqlTableMode?

IscanderChe
  • 28 апреля 2022 г. 13:54

QSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase())

d
  • 28 апреля 2022 г. 19:16

Мой вопрос был про объект класса DataBase. Как он связывается с объектом класса QSqlTableModel.Можете указать строчку в коде?

IscanderChe
  • 28 апреля 2022 г. 19:36

Объект QSqlDatabase() устанавливается глобально, для всего кода. DataBase, соответственно, делает то же самое, только с помощью своих методов, которые используются в mainwindow.cpp, а сам объект подключается и объявляется в mainwindow.h. Затем через таблицы из БД происходит связь с моделью. Это про первый мой ответ.

Если вы, к примеру, открываете несколько баз данных в одном приложении, то вы можете указать при создании модели, какую именно базу данных использовать. Это про мой второй ответ вам.

АС
  • 4 августа 2022 г. 15:33
  • (ред.)

error insert into TableExample
" Количество параметров не совпадает"

Я путь свой прописывала и даже бд удаляла, чтобы заново сделать, не работает. (всё остальное как у вас... Вроде как. Хотя я так и не увидела, где используется closeDataBase())

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь