Evgenii Legotckoi
Evgenii Legotckoi14 серпня 2015 р. 23:44

Qt/C++ - Урок 004. QSqlTableModel – Як представити таблицю з бази даних?

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

  • QSqlQueryModel - модель, яка формує таблицю шляхом завдання сирого SQL-запиту. Може бути корисною при формуванні особливо витончених фільтрів та компіляції інформації з різних таблиць бази даних. Про неї докладніше у наступних уроках.
  • QSqlTableModel - предмет нашої розмови у цій статті. Модель, яка формує таблицю на ім'я тієї таблиці, що існує у базі даних. З мінусів можна відзначити відсутність методів підключення зв'язків з іншими таблицями, щоб підставляти значення поля з інших таблиць по 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.

#-------------------------------------------------
#
# Project created by QtCreator 2015-08-10T16:08:24
#
#-------------------------------------------------

QT       += core
QT       += gui
QT       += sql

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = DataBase
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp \
    database.cpp

HEADERS  += mainwindow.h \
    database.h

FORMS    += mainwindow.ui

main.cpp

Файл використовується у проекті, створений за замовчуванням.

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

У цьому заголовному файлі міститься оголошення об'єкта QSqlTableModel та DataBase , допоміжного класу, що застосовується для роботи з інформацією, яка розміщена в базі даних. Крім них оголошені методи для ініціалізації зовнішнього вигляду та моделі QSqlTableModel нашої програми.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSqlTableModel>
/* Подключаем заголовочный файл для работы с информацией, которая помещена в базу данных */
#include "database.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow  *ui;
    /* В проекте используются объекты для взаимодействия с информацией в базе данных
     * и моделью представления таблицы базы данных
     * */
    DataBase        *db;
    QSqlTableModel  *model;

private:
    /* Также присутствуют два метода, которые формируют модель
     * и внешний вид TableView
     * */
    void setupModel(const QString &tableName, const QStringList &headers);
    void createUI();
};

#endif // MAINWINDOW_H

mainwindow.cpp

Вихідний файл, де відбувається все основне дійство по взаємодії з моделлю представлення даних.

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* Первым делом необходимо создать объект, который будет использоваться для работы с данными нашей БД
     * и инициализировать подключение к базе данных
     * */
    db = new DataBase();
    db->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)); 
        // Вставляем данные в БД
        db->inserIntoTable(data);
    }

    /* Инициализируем модель для представления данных
     * с заданием названий колонок
     * */
    this->setupModel(TABLE,
                     QStringList() << trUtf8("id")
                                   << trUtf8("Дата")
                                   << trUtf8("Время")
                                   << trUtf8("Рандомное число")
                                   << trUtf8("Сообщение")
               );

    /* Инициализируем внешний вид таблицы с данными
     * */
    this->createUI();
}

MainWindow::~MainWindow()
{
    delete ui;
}

/* Метод для инициализации модеи представления данных
 * */
void MainWindow::setupModel(const QString &tableName, const QStringList &headers)
{
    /* Производим инициализацию модели представления данных
     * с установкой имени таблицы в базе данных, по которому
     * будет производится обращение в таблице
     * */
    model = new QSqlTableModel(this);
    model->setTable(tableName);

    /* Устанавливаем названия колонок в таблице с сортировкой данных
     * */
    for(int i = 0, j = 0; i < model->columnCount(); i++, j++){
        model->setHeaderData(i,Qt::Horizontal,headers[j]);
    }
    // Устанавливаем сортировку по возрастанию данных по нулевой колонке
    model->setSort(0,Qt::AscendingOrder);
}

void MainWindow::createUI()
{
    ui->tableView->setModel(model);     // Устанавливаем модель на TableView
    ui->tableView->setColumnHidden(0, true);    // Скрываем колонку с id записей
    // Разрешаем выделение строк
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    // Устанавливаем режим выделения лишь одно строки в таблице
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    // Устанавливаем размер колонок по содержимому
    ui->tableView->resizeColumnsToContents();
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tableView->horizontalHeader()->setStretchLastSection(true);

    model->select(); // Делаем выборку данных из таблицы
}

база даних.h

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

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

#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

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

#include "database.h"

DataBase::DataBase(QObject *parent) : QObject(parent)
{

}

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;
}

Підсумок

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

Зовнішній вигляд програми з QSqlTableModel

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

И
  • 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
  • 07 травня 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
  • 07 травня 2017 р. 21:31

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

z
  • 07 травня 2017 р. 22:23

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

Evgenii Legotckoi
  • 07 травня 2017 р. 22:25

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

v
  • 27 квітня 2018 р. 04:20

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

v
  • 27 квітня 2018 р. 04: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
  • 08 жовтня 2018 р. 14:06

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

B
  • 08 жовтня 2018 р. 14:07

Все понял

Evgenii Legotckoi
  • 08 жовтня 2018 р. 14:07

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

B
  • 08 жовтня 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
  • 08 жовтня 2018 р. 16:49

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

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;
    }
}


B
  • 08 жовтня 2018 р. 20:21
bool DataBase::openDataBase()
{
    db = QSqlDatabase::addDatabase("QSQLITE");

    db.setHostName(DATABASE_HOSTNAME);
    db.setDatabaseName("C:/Users/esmit/Documents/Qt/DataBase/" DATABASE_NAME);

    if(db.open())
        return true;
    else
        return false;
}


B
  • 08 жовтня 2018 р. 20:27

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

Evgenii Legotckoi
  • 08 жовтня 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 ничего нет, кроме заголовка.

QVariant MySqlTableModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
        QTime time = this->data(index, Qt::DisplayRole).toTime();
        QString str = time.toString("hh:mm:ss");
        return str;
    }
    else
        return QVariant();
}
Evgenii Legotckoi
  • 16 січня 2019 р. 13:51
  • (відредаговано)

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

QVariant MySqlTableModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
        QTime time = QSqlTableModel::data(index, Qt::DisplayRole).toTime();
        QString str = time.toString("hh:mm:ss");
        return str;
    }

    return QSqlTableModel::data(index, role);
}
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
  • (відредаговано)

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

bool Model::update_in_db(Data *item)
{
    QSqlQuery query;
    query.setForwardOnly(true);
    query.prepare("UPDATE myDB SET      \n"
                  " code_all = :code,                     \n"
                  " date = :date,                                \n"
                  " person = :person,                        \n"
                  "WHERE id = :id;                                \n"
                  );

    query.bindValue(":code", item->Code_all());
    query.bindValue(":date", item->Date());
    query.bindValue(":person", item->Person());

    if(query.exec()) {
        return true;
    } else {
        qCritical() << query.lastError().databaseText();
        qCritical() << query.lastError().driverText();
        qCritical() << query.lastError().nativeErrorCode();

        return false;
    }
}

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

Model::delete_from_db()
{
    QSqlQuery query;
    query.setForwardOnly(true);
        query.prepare("DELETE FROM myDB WHERE id = :ID ;");
        query.bindValue(":ID", currentIndex.row());

        if(!query.exec()){
            qCritical() << query.lastError().databaseText().toUtf8().data();
            qCritical() << query.lastError().driverText();
            qCritical() << query.lastError().nativeErrorCode();
            return false;
        } else {
            return true;
        }
        return false;
}
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. Затем через таблицы из БД происходит связь с моделью. Это про первый мой ответ.

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

АС
  • 04 серпня 2022 р. 15:33
  • (відредаговано)

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

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

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
B
  • Bogdannn
  • 28 березня 2024 р. 05:21

C++ - Тест 002. Константы

  • Результат:16бали,
  • Рейтинг балів-10
B
  • Bogdannn
  • 28 березня 2024 р. 05:15

C++ - Тест 001. Первая программа и типы данных

  • Результат:46бали,
  • Рейтинг балів-6
FL

C++ - Тест 006. Перечисления

  • Результат:80бали,
  • Рейтинг балів4
Останні коментарі
k
kmssr09 лютого 2024 р. 05:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 12:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 21:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 19:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 грудня 2023 р. 08:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
P
Pisych27 лютого 2023 р. 15:04
Как получить в массив значения из связанной модели? Спасибо, разобрался:))
AC
Alexandru Codreanu19 січня 2024 р. 22:57
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCT27 грудня 2023 р. 19:57
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
Дмитрий10 січня 2024 р. 15:18
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii Legotckoi12 грудня 2023 р. 17:48
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Слідкуйте за нами в соціальних мережах