Евгений Легоцкой24 ноября 2015 г. 9:11

QML - Урок 016. База данных SQLite и работа с ней в QML Qt

Небольшой пример по работе с базой данных в QML Qt . В данном уроке сводится воедино информация о применении сигналов и слотов в QML Qt , о доступе к C++ классам из QML слоя, реализации интерфейса приложения на QML, а также о реализации модели/представлении для таблицы базы данных.

База данных содержит таблицу со списком людей, в которой имеется четыре колонки:

  • id (INTEGER) - уникальный номер записи;
  • FirstName (VARCHAR (255)) - Имя;
  • SurName (VARCHAR (255)) - Фамилия;
  • Nik (VARCHAR (255)) - Ник.

Приложение должно реализовывать удаление и добавление записей в базу данных через интерфейс приложения. Для добавления записей в Базу данных будет использоваться три поля для ввода данных и кнопка, которая инициализирует добавление данных в базу данных SQL . Добавление записей в таблицу осуществляется через класс обёртку предназначенным для этого методом.Также в приложении присутствует класс ListModel , который реализует модель представления данных для отображения информации в TableView в слое QML.

Структура проекта

  • QmlDataBase.pro - профайл проекта;
  • database.h - заголовочный файл класса-обёртки для работы с базой данных;
  • database.cpp - файл исходных кодов класса-обёртки для работы с базой данных;
  • listmodel.h - заголовочный файл модели данных;
  • listmodel.cpp - файл исходных кодов модели данных;
  • main.cpp - основной файл исходных кодов приложения;
  • main.qml - основной файл qml.

QmlDataBase.pro

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

TEMPLATE = app

QT += qml quick widgets sql

SOURCES += main.cpp \
    database.cpp \
    listmodel.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 \
    listmodel.h

main.cpp

В основном файле исходных кодов подключаем класс-обёртку для работы с базой данных и класс модели данных. Объекты этих классов необходимо объявить и инициализировать в данном файле, а также настроить доступ к этим объектам и их свойствам из QML слоя.

После того, как доступ к объектам настроен, из QML слоя становятся доступны следующие свойства и функции объекта, которые объявлены в его классе в качестве:

  1. Сигналов
  2. Слотов
  3. А также функции, которые фигурируют в макросе Q_PROPERTY
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "database.h"
#include "listmodel.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;

    // Подключаемся к базе данных
    DataBase database;
    database.connectToDataBase();

    // Объявляем и инициализируем модель данных
    ListModel *model = new ListModel();

    // Обеспечиваем доступ к модели и классу для работы с базой данных из QML
    engine.rootContext()->setContextProperty("myModel", model);
    engine.rootContext()->setContextProperty("database", &database);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

database.h

В данном классе объявлены методы для работы с базой данных:

  • методы для подключения к базе данных, её восстановления;
  • методы для добавления записи в базу данных;
  • методы для удаления записей в таблице данных.

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

Данный класс реализует паттерн проектирования Facade, хотя и не полностью, поскольку как я уже сказал, что одна из сущностей QSqlQueryModel используется в модели данных в этом уроке.

ВНИМАНИЕ!!! - файл базы данных создается в папке 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   "NameDataBase"
#define DATABASE_NAME       "Name.db"

#define TABLE                   "NameTable"         // Название таблицы
#define TABLE_FNAME             "FisrtName"         // Вторая колонка
#define TABLE_SNAME             "SurName"           // Третья колонка
#define TABLE_NIK               "Nik"               // Четвертая колонка

// Первая колонка содержит Autoincrement ID

class DataBase : public QObject
{
    Q_OBJECT
public:
    explicit DataBase(QObject *parent = 0);
    ~DataBase();
    /* Методы для непосредственной работы с классом
     * Подключение к базе данных и вставка записей в таблицу
     * */
    void connectToDataBase();

private:
    // Сам объект базы данных, с которым будет производиться работа
    QSqlDatabase    db;

private:
    /* Внутренние методы для работы с базой данных
     * */
    bool openDataBase();        // Открытие базы данных
    bool restoreDataBase();     // Восстановление базы данных
    void closeDataBase();       // Закрытие базы данных
    bool createTable();         // Создание базы таблицы в базе данных

public slots:
    bool inserIntoTable(const QVariantList &data);      // Добавление записей в таблицу
    bool inserIntoTable(const QString &fname, const QString &sname, const QString &nik);
    bool removeRecord(const int id); // Удаление записи из таблицы по её id
};

#endif // DATABASE_H

database.cpp

Инициализация подключения к базе данных производится методом connectToDataBase() . Название таблицы, базы данных, файла, а также колонок в таблице определены в директивах define в заголовочном файле.

#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()){
        // Производим восстановление базы данных
        return (this->createTable()) ? true : false;
    } 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_FNAME     " VARCHAR(255)    NOT NULL,"
                            TABLE_SNAME     " VARCHAR(255)    NOT NULL,"
                            TABLE_NIK       " 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_FNAME ", "
                                             TABLE_SNAME ", "
                                             TABLE_NIK " ) "
                  "VALUES (:FName, :SName, :Nik)");
    query.bindValue(":FName",       data[0].toString());
    query.bindValue(":SName",       data[1].toString());
    query.bindValue(":Nik",         data[2].toString());

    // После чего выполняется запросом методом exec()
    if(!query.exec()){
        qDebug() << "error insert into " << TABLE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    }
    return false;
}

/* Второй метод для вставки записи в базу данных
 * */
bool DataBase::inserIntoTable(const QString &fname, const QString &sname, const QString &nik)
{
    QVariantList data;
    data.append(fname);
    data.append(sname);
    data.append(nik);

    if(inserIntoTable(data))
        return true;
    else
        return false;
}

/* Метод для удаления записи из таблицы
 * */
bool DataBase::removeRecord(const int id)
{
    // Удаление строки из базы данных будет производитсья с помощью SQL-запроса
    QSqlQuery query;

    // Удаление производим по id записи, который передается в качестве аргумента функции
    query.prepare("DELETE FROM " TABLE " WHERE id= :ID ;");
    query.bindValue(":ID", id);

    // Выполняем удаление
    if(!query.exec()){
        qDebug() << "error delete row " << TABLE;
        qDebug() << query.lastError().text();
        return false;
    } else {
        return true;
    }
    return false;
}

listmodel.h

Модель данных является классом, наследованным от QSqlQueryModel, в котором переопределены методы data() и roleNames(). Также в классе перечислены роли, по которым передается информация в представление в интерфейсе. Для удаления данных необходимо получать уникальный ID записи, который вытягивается из модели по методом getID() по роли и номеру строки, который был передан из представления. Для получения данных из Базы данных используется метод updateModel(), в котором устанавливается SQL-запрос к Базе данных.

#ifndef LISTMODEL_H
#define LISTMODEL_H

#include <QObject>
#include <QSqlQueryModel>

class ListModel : public QSqlQueryModel
{
    Q_OBJECT
public:
    /* Перечисляем все роли, которые будут использоваться в TableView
     * Как видите, они должны лежать в памяти выше параметра Qt::UserRole
     * Связано с тем, что информация ниже этого адреса не для кастомизаций
     * */
    enum Roles {
        IdRole = Qt::UserRole + 1,      // id
        FNameRole,                      // имя
        SNameRole,                      // фамилия
        NikRole                         // ник
    };

    // объявляем конструктор класса
    explicit ListModel(QObject *parent = 0);

    // Переопределяем метод, который будет возвращать данные
    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

protected:
    /* хешированная таблица ролей для колонок.
     * Метод используется в дебрях базового класса QAbstractItemModel,
     * от которого наследован класс QSqlQueryModel
     * */
    QHash<int, QByteArray> roleNames() const;

signals:

public slots:
    void updateModel();
    int getId(int row);
};

#endif // LISTMODEL_H

listmodel.cpp

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

#include "listmodel.h"
#include "database.h"

ListModel::ListModel(QObject *parent) :
    QSqlQueryModel(parent)
{
    this->updateModel();
}

// Метод для получения данных из модели
QVariant ListModel::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> ListModel::roleNames() const {
    /* То есть сохраняем в хеш-таблицу названия ролей
     * по их номеру
     * */
    QHash<int, QByteArray> roles;
    roles[IdRole] = "id";
    roles[FNameRole] = "fname";
    roles[SNameRole] = "sname";
    roles[NikRole] = "nik";
    return roles;
}

// Метод обновления таблицы в модели представления данных
void ListModel::updateModel()
{
    // Обновление производится SQL-запросом к базе данных
    this->setQuery("SELECT id, " TABLE_FNAME ", " TABLE_SNAME ", " TABLE_NIK " FROM " TABLE);
}

// Получение id из строки в модели представления данных
int ListModel::getId(int row)
{
    return this->data(this->index(row, 0), IdRole).toInt();
}

main.qml

В Qt парадигма модели/вида/контроллера изменена на модель/представление. Представление объединяет в себе контроллер и вид. Таким образом, main.qml обрабатывает информацию, которую вводит пользователь и передаёт её в backend в удобоваримом виде, но если учесть, что к объекту класса database дан доступ из QML слоя, а добавление данных производится через функцию слот, то условно можно принять, что контроллер реализован в представлении.

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    // Слой с TaxtField`ами и Button для занесения записей в базу данных
    RowLayout {
        id: rowLayout
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.margins: 5

        spacing: 10

        Text {text: qsTr("Имя")}
        TextField {id: fnameField}
        Text {text: qsTr("Фамилия")}
        TextField { id: snameField}
        Text {text: qsTr("НИК")}
        TextField {id: nikField}

        Button {
            text: qsTr("Добавить")

            // Вносим новую запись в базу данных
            onClicked: {
                database.inserIntoTable(fnameField.text , snameField.text, nikField.text)
                myModel.updateModel() // И обновляем модель данных с новой записью
            }
        }
    }

    TableView {
        id: tableView
        anchors.top: rowLayout.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        anchors.margins: 5

        TableViewColumn {
            role: "fname"
            title: "Имя"
        }
        TableViewColumn {
            role: "sname"
            title: "Фамилия"
        }
        TableViewColumn {
            role: "nik"
            title: "НИК"
        }

        model: myModel

        // Настройка строки в TableView для перехавата левого клика мыши
        rowDelegate: Rectangle {
            anchors.fill: parent
            color: styleData.selected ? 'skyblue' : (styleData.alternate ? 'whitesmoke' : 'white');
            MouseArea {
                anchors.fill: parent
                acceptedButtons: Qt.RightButton | Qt.LeftButton
                onClicked: {
                    tableView.selection.clear()
                    tableView.selection.select(styleData.row)
                    tableView.currentRow = styleData.row
                    tableView.focus = true

                    switch(mouse.button) {
                    case Qt.RightButton:
                        contextMenu.popup() // Вызываем контексткное меню
                        break
                    default:
                        break
                    }
                }
            }
        }
    }

    // Контекстно меню предлагает удаление строки из базы данных
    Menu {
        id: contextMenu

        MenuItem {
            text: qsTr("Удалить")
            onTriggered: {
                /* Вызываем диалоговое окно,
                 * которое уточнит намерение удалить строку из базы данных
                 * */
                dialogDelete.open()
            }
        }
    }

    // Диалог подтверждения удаления строки из базы данных
    MessageDialog {
        id: dialogDelete
        title: qsTr("Удаление записи")
        text: qsTr("Подтвердите удаление записи из журнала")
        icon: StandardIcon.Warning
        standardButtons: StandardButton.Ok | StandardButton.Cancel

        // При положительном ответе ...
        onAccepted: {
            /* ... удаляем строку по id,
             * который забираем из модели данных
             * по номеру строки в представлении
             * */
            database.removeRecord(myModel.getId(tableView.currentRow))
            myModel.updateModel();  // Обновляем модель данных
        }
    }
}

Итог

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

Кроме этого рекомендую почитать подробнее о паттерне проектирования Facade и посмотреть более полный вариант реализации данного паттерна в следующей статье: Шаблон проектирования "Фасад"

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Поддержать автора Donate
Добрый день, запустил ваш пример при нажатии на кнопку получаю вот эту ошибку

ASSERT failure in QList<T>::operator[]: "index out of range", file ../../Qt5.11.0/5.11.0/gcc_64/include/QtCore/qlist.h, line 545

Подскажите пожалуйста в чём может быть дело на что она указывает где искать ?
Разобрался, не правильное добавление записи в БД а именно лишний запрос query.bindValue стоял в методе inserIntoTable.
W
  • #
  • 15 июня 2018 г. 10:08

Добрый день, пытаюсь передать текст из QML слоя в C++ при нажатии на кнопку. При нажатии на кнопку выводит ошибку.


TypeError: Property 'remove_db' of object [object Object] is not a function
Не могу понять в чем ошибка(новичок в Qt) Если есть возможно можно простой пример как передать текст или число из QML лося в C++ или где ошибка в моем коде. Спасибо заранее)
QML:

import QtQuick 2.0
import Sailfish.Silica 1.0
import QtPositioning 5.3
import QtLocation 5.0
import QtQuick 2.0
import QtWebKit 3.0
import MyModule 1.0

Page{
    id: pageMenu
    GPSCoor{
        id:data
        // @disable-check M16
        onSendToTime:
        {
            myModel.append({"time" : data_time_real_time})
        }
    }

    Rectangle{
        id: kv_menu
        anchors.fill: parent                                                 //Привязка к радителю
        color: "steelblue"
        ListView
        {
            id: myListView
            anchors
            {
                top: kv_menu.top
                right: kv_menu.right
                left: kv_menu.left
                bottom: buttonHistory.top

                rightMargin: 30
                leftMargin: 30
                topMargin: 30
                bottomMargin: 100
            }

            model: myModel
            delegate: Item{
                id:itemrec
                width: myListView.width
                height: 90

                Button{
                    id: rectest
                    anchors.margins: 6
                    anchors.fill: parent

                    Text
                    {
                        id:textNuj
                        objectName: "textZae"
                        color: "white"
                        font.pixelSize: 40
                        text: time + " - " + (model.index+1)
                        anchors.horizontalCenter: rectest.horizontalCenter
                        anchors.verticalCenter: rectest.verticalCenter
                    }
                    onClicked:
                    {
//                        console.log("text - " + text)
//                        console.log("modelN - "+ model.index)
//                        console.log("textNuj - " + textNuj.text)
//                        //pageStack.push(dialog)
                        data.remove_db(model.index);
                    }
                }
            }
        }
        ListModel
        {
            id:myModel
        }
        Button
        {
            id: buttonHistory
            height: 90
            anchors{
                right: kv_menu.right
                left: kv_menu.left
                bottom: kv_menu.bottom

                rightMargin: 30
                leftMargin: 30
                bottomMargin: 30
            }
            Label{
                color: "white"
                text: "Показать треки"
                anchors.horizontalCenter: buttonHistory.horizontalCenter
                anchors.verticalCenter: buttonHistory.verticalCenter
            }
            onClicked: {
                data.pageMapX()
            }
        }
    }
    Component{
        id: dialog
        Dialog {
            id: winDialog
            property string name

            Rectangle{
                id:winDialogRec1
                color: "steelblue"
                anchors.fill: parent
                property string name
                DialogHeader
                {   id: dialogHeader
                    acceptText: qsTr("Принять")
                    cancelText: qsTr("Отменить")
                }
                Rectangle{
                    id:winDialogRec
                    color: "steelblue"
                    anchors.horizontalCenter: parent.horizontalCenter
                    anchors.top: parent.top
                    anchors.topMargin: 400

                    Label{
                        id:label1
                        anchors{
                           horizontalCenter: winDialogRec.horizontalCenter
                           top: parent.top
                        }
                        color: "white"
                        text: "Вы действительно хотите удалить трек?"
                    }
                    Label{
                        id: label2
                        anchors{
                            horizontalCenter: winDialogRec.horizontalCenter
                            top: parent.top

                            topMargin: 250

                        }
                        color: "white"
                        text: name
                    }
                    Button{
                        width: parent / 2 - 45
                        anchors{
                            top: parent.top
                            left: parent.left
                            topMargin: 120
                            leftMargin: 30
                        }
                        text: "Нет"
                        onClicked:
                        {
                           label2.text = "Нет, не удалять этот трек"
                        }
                    }
                    Button{

                        width: parent / 2 - 45
                        anchors{
                            top: parent.top
                            right: parent.right
                            topMargin: 120
                            rightMargin: 30
                        }

                        text: "Да"
                        onClicked:
                        {
                           label2.text = "Да, удалить этот трек"
                         }
                    }

                }

            }

        }
    }
}
Заголовок:
#ifndef GPSCOOR_H
#define GPSCOOR_H
#include <QObject>
#include <QDebug>

class GPSCoor: public QObject
{
    Q_OBJECT
    Q_PROPERTY(double x_cor READ  getSomePropertyX   WRITE setSomePropertyX   NOTIFY sendToQml)     //Для обменна даными с переменной x_cor
    Q_PROPERTY(double y_cor READ  getSomePropertyY   WRITE setSomePropertyY   NOTIFY sendToQml)     //Для обменна даными с переменной y_cor
    Q_PROPERTY(QString way   READ  getSomePropertyWay WRITE setSomePropertyWay NOTIFY sendToWay)     //Для обменна даными о времени t
    Q_PROPERTY(QString data_time_real_time  READ  getSomePropertyTime   WRITE setSomePropertyTime   NOTIFY sendToTime)     //Для обменна даными о расстоянии m

    //    Q_PROPERTY(double arreyXY READ  getSomePropertyX WRITE setSomePropertyX NOTIFY sendToQml)     //Для обменна даными с переменной x_cor

public:
    explicit GPSCoor(QObject *parent = 0);
    Q_INVOKABLE void remove_db();

    double getSomePropertyX()const;                                                             //Для обменна даными с переменной x_cor
    double getSomePropertyY()const;                                                             //Для обменна даными с переменной y_cor
    QString getSomePropertyTime()const;                                                          //Для обменна даными о времени t
    QString getSomePropertyWay()const;                                                           //Для обменна даными о расстоянии m

    void setSomePropertyY(const double &);                                                      //Для обменна даными с переменной y_cor
    void setSomePropertyX(const double &);                                                      //Для обменна даными с переменной x_cor
    void setSomePropertyTime(const QString &);                                                   //Для обменна даными о времени t
    void setSomePropertyWay(const QString &);                                                    //Для обменна даными о расстоянии m

    void creat_db();                                                                            //Для создания базы данных и записи данных
    void insert_db();                                                                           //Для извлечения данных и бызы
    void distance();

    //Для выисления растояния от точки до точки
signals:
    void sendToQml(double);                                                                     //Сигнал для передачи данных в qml
    void sendToWay(QString);
    void sendToTime(QString);

public slots:

    void reciveX();                                                                             //Сигнал для получения данных с qml(FirstPage)
    void reciveTime();                                                                          //Сигнал для получения данных о времени
    //   void reciveWay();
    void pageMapX();                                                                            //Сигнал для получения данных с qml(Map)


private:
    QString data_time_real_time;
    QString way;
    double x_cor;                                                                               //Перменная координата х_cor
    double y_cor;                                                                               //Перменная координата y_cor
    int data_time;                                                                              //Перменная для измерении времени

    double Way_point=0;

    float CMX11 = 0;
    float CMY11 = 0;
    float CMX21 = 0;
    float CMY21 = 0;
    const float pi = 3.141592653589793;
    const float radius = 6378.16;
    double num =  1;                                                                               //Перменная счетчик для цыкла
    double n = 1000;
    double z = 2;
    //    double arreyXY[2][1000];

};
#endif // GPSCOOR_H
С++:
#include "gpscoor.h"
#include <QObject>
#include <QDebug>
#include "QtSql/QSqlDatabase"
#include "QSqlQuery"
#include <QtSql>
#include <QTime>
#include <QLocale>
#include <QDateTime>
#include <QtMath>
#include <math.h>

GPSCoor::GPSCoor(QObject *parent): QObject(parent)
{


}

void GPSCoor::remove_db()
{

    qDebug()<<"remuve_db() = "<<data_time_real_time<<endl;
    QSqlQuery query;                                                     //Осуществляем запрос
    // Удаление строки из базы данных будет производитсья с помощью SQL-запроса


       // Удаление производим по id записи, который передается в качестве аргумента функции
       query.prepare("DELETE FROM my_ta WHERE data_time= :data_time;");
       query.bindValue(":data_time", data_time_real_time);

       // Выполняем удаление
       if(!query.exec()){
           qDebug() << "error delete row " << "my_ta";
           qDebug() << query.lastError().text();

       } else
       {

       }

    //    query.exec("SELECT id, data_time ,x_cor, y_cor FROM my_ta ");
//    while (query.next())                                                 //Выводим значения из запроса
//    {
//        int id = query.value(0).toInt();                                 //Получаю данные из БД
//        data_time = query.value(1).toInt();                          //Получаю данные из БД
//        x_cor = query.value(2).toDouble();                               //Получаю данные из БД
//        y_cor = query.value(3).toDouble();                               //Получаю данные из БД
//        QString data_time_2 = QString::number(data_time);
//        if(data_time_real_time == data_time_2)
//        {
//            query.exec("DELETE FROM jobs WHERE data_time = ?");
//            query.addBindValue(data_time);
//            qDebug()<<"Delete for BD good"<<endl;
//        }
//        else{
//            qDebug()<<"Error Delete for BD bad"<<endl;
//        }
//    }

}

void GPSCoor::reciveTime()
{
   emit sendToTime(data_time_real_time);
}

double GPSCoor::getSomePropertyX()const                 //Для обменна даными с переменной x_cor
{
    return x_cor;
}

double GPSCoor::getSomePropertyY()const                 //Для обменна даными с переменной y_cor
{    
    return y_cor;
}

QString GPSCoor::getSomePropertyWay()const                 //Для обменна даными с переменной way
{
    return way;
}

QString GPSCoor::getSomePropertyTime()const                 //Для обменна даными с переменной time
{
    return data_time_real_time;
}

void GPSCoor::setSomePropertyX(const double &i)         //Для обменна даными с переменной x_cor
{
    x_cor = i;
    emit sendToQml(x_cor);
}

void GPSCoor::setSomePropertyY(const double &i)         //Для обменна даными с переменной y_cor
{
    y_cor = i;
    emit sendToQml(y_cor);
}

void GPSCoor::setSomePropertyWay(const QString &i)         //Для обменна даными с переменной way
{
    way = i;
    emit sendToWay(way);
}

void GPSCoor::setSomePropertyTime(const QString &i)         //Для обменна даными с переменной time
{
    data_time_real_time = i;
    emit sendToTime(data_time_real_time);
}

void GPSCoor::reciveX()                                 //Принимаю данные из QML(FirstPage)
{
    emit sendToQml(x_cor);                              //Принимаю данные в QML(FirstPage)
    emit sendToQml(y_cor);                              //Принимаю данные в QML(FirstPage)
    emit creat_db();                                    //Для создания и записи БД на стороне С++
    //emit insert_db();                                 //Для извлечения данных и бызы на стороне С++
}

void GPSCoor::pageMapX()                                //Принимаю данные из QML(Map)
{
    emit insert_db();                                   //Для извлечения данных и бызы на стороне С++
}

void GPSCoor::creat_db()                                //Создаем SQLite
{
    QTime time = QTime::currentTime();                  //Создаю обект для получения реальное время
    data_time = time.msecsSinceStartOfDay();            //Записываю время в переменную в формате миллисекунд
    qDebug()<<data_time<<endl;

    QSqlDatabase dbase = QSqlDatabase::addDatabase("QSQLITE");          //Создая обект для QSQLite
    dbase.setDatabaseName("test_2.sqlite");                             //Создаю БД
    if (!dbase.open()) {                                                //Проверяю БД
        qDebug() << "Error db";
    }else{
        qDebug()<<"Good db";
    }

    QSqlQuery a_query;
    // DDL query
    QString str = "CREATE TABLE my_ta ("               //создаю таблицу
            "id integer PRIMARY KEY NOT NULL, "
            "data_time integer,"
            "x_cor double, "
            "y_cor double"
            ");";
    bool b = a_query.exec(str);                        //Проверка на создания
    if (!b) {
        qDebug() << "error2!";
    }
    else{
        qDebug()<<"send2";
    }

    //        QString str_insrt = "INSERT INTO my_ta (data_time,x_cor,y_cor) VALUES (%1, %2, %3);";             // Записываю данные в Таблицу
    //        str = str_insrt.arg(data_time)
    //                .arg(x_cor)
    //                .arg(y_cor);
    //        b = a_query.exec(str);
    //        if (!b) {
    //            qDebug() << "error3";
    //        }else{
    //            qDebug()<<"Send3";
    //        }
}

void GPSCoor::insert_db()                               //Вывести данные из db и отправить в map.qml
{

    QSqlQuery query;                                                     //Осуществляем запрос
    query.exec("SELECT id, data_time ,x_cor, y_cor FROM my_ta ");
    while (query.next())                                                 //Выводим значения из запроса
    {

        int id = query.value(0).toInt();                                 //Получаю данные из БД
        data_time = query.value(1).toInt();                              //Получаю данные из БД
        x_cor = query.value(2).toDouble();                               //Получаю данные из БД
        y_cor = query.value(3).toDouble();                               //Получаю данные из БД

        if(id == num)
        {
            emit sendToQml(x_cor);                                      //Отправляю данные в QML(Map)
            emit sendToQml(y_cor);                                      //Отправляю данные в QML(Map)

            QTime time = QTime::fromMSecsSinceStartOfDay(data_time);
            data_time_real_time = time.toString("hh:mm:ss"); //str = "20:04:23.003"
            emit sendToTime(data_time_real_time);

            qDebug()<< "id - "<< id << endl;                            //простая проерка данных, вывожу на экран
            qDebug()<< "data_time_real_time - "<< data_time_real_time << endl;              //простая проерка данных, вывожу на экран
            qDebug()<< "y_cor - "<< x_cor << endl;
            qDebug()<< "x_cor - "<< y_cor << endl;
            //Вычисление растояния между 2 координатами гипатенуза
            CMX11 = y_cor;
            CMY11 = x_cor;
            if(id==1)
            {
//                CMX21 = y_cor;
//                CMY21 = x_cor;
            }
            else{
               emit distance();

                qDebug()<<"Way (км)  "<< Way_point << endl;
            }
            CMX21 = CMX11;
            CMY21 = CMY11;

        }
        else
        {
        }

    }
    num += 20;                       //Увеличиваю num++
}
void GPSCoor::distance(){
    Way_point = round((Way_point + sqrt(pow((CMX21 - CMX11),2) + pow((CMY21 - CMY11),2))*100)*100)/100;
    way = QString::number(Way_point);
    emit sendToWay(way);
}

что-то мне сдаётся, что здесь просто пересобрать проект нужно с удалением build каталога

ММ

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

Добрый день. В статье про это как раз и говорится. Там для этого есть метод inserIntoTable и он в сатье используется.

D:

Добрый день, пытаюсь разобраться и подргнать пример под себя. Есть бд с огромным количеством полей. В приложении на виджетах при использовании QTableView все работает и путем простого sql запроса может вывести сразу всю таблицу. В qml же приложении я так понял жизненно необходимо определять роли. от этого никак не уйти? И как поступать когда ролей порядка 40, а таблиц много.
Второй вопрос : как ваш класс listmodel связывается с бд, т.е. каким образом он понимает , что она существует. проштудировал ваш пример и нигде нет ни ссылки ни намека на класс database, кроме подключения хедера. При попытке воспроизвести ваш класч listview в методе update в дебаге выдает сообщение о том что не удалось открыть бд. Заранее спасибо

РГ

Добрый день! можно как то обойтись без метода updateModel()? После вызова этого метода происходит перерисовка страницы(если я правильно понимаю), и все элементы, например, CheckBox перерисовываются и это очень заметно пользователю, либо если элемент имеет свойство скрыть/отобразить, то он принимает свое первоначальное состояние, а если в этом элементе работаешь и он после updateModel() скрывается не очень хорошо, опять разворачивай. Пробывал emit dataChanged(index, index, {role}) но ничего не происходит, модель не обновляет данные, только после updateModel(), происходит обновление модели, хотя в qml я меняю значение модели onClicked: {model.flag = checked;}. Может кто что подскажет?

updateModel() используется для выборки данных из базы данных, поэтому естественно, что если не выбирать данные, то ничего не обновится.
Что касается сохранения скрытого или развёрнутого состояния, то там нужно разбираться с временным сохранением состояния и после использования updateModel() восстанавливать состояние таблицы.
Проблема в том, что просто - это не сделать. Потребуется приличное количество дополнительного кода.

Комментарии

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

Позвольте мне порекомендовать вам отличный хостинг, на котором расположен EVILEG.

В течение многих лет Timeweb доказывает свою стабильность.

Для проектов на Django рекомендую VDS хостинг

Посмотреть Хостинг
k
  • knobu
  • 23 сентября 2020 г. 2:34

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

  • Результат:60баллов,
  • Очки рейтинга-1
k
  • knobu
  • 23 сентября 2020 г. 2:21

C++ - Тест 005. Структуры и Классы

  • Результат:91баллов,
  • Очки рейтинга8
k
  • knobu
  • 23 сентября 2020 г. 2:16

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
Последние комментарии

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

QSqlTableModel выполняет ряд стандартных операций для одной таблицы из базы данных. Поэтому там и реализован функционал по удалению и редактированию. QSqlQueryModel позволяет выполнить запр…
VB

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Добрый день. Хотел спросить вот что. Создал проект на основе QAbstractTableModel. В MainWindow cоответственно создал модель и связал с представлением. Поиск веду по списку элементов модели,…

QCheckBox в качестве делегата QTableView

До тех пор, пока у вас проект содержит только одну таблицу, или несколько то может быть. Когда их будет 1000 и чекбоксы в разных колонках, то без делегатов и переопределения возвращаемых ре…
D
  • Damir
  • 20 сентября 2020 г. 15:34

QCheckBox в качестве делегата QTableView

bool Node::setData(const QModelIndex& index, const QVariant& value, int role){ switch (index.column()) { case 0: switch (role) { case Qt::CheckStateRole:// <- т…
VB

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

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

Как в Qt в qmenu добавить scrollarea

Вот это наследованный класс меню. Но посути это обычное меню. #pragma once#include <QtWidgets>class TransMenu : public QMenu { Q_OBJECTpublic: TransMenu(QWidget* parent = …

Как в qml работать с динамически созданными потомками?

В QML есть сборщик мусора, он может удалять объекты не сразу а по ппрошествии времени. Попробуйте при удалении вызывать сборщик мусора принудительно через gc()
VB

Как запустить программу с базой данных PostgreSQL на другом компьютере

Не требует никакую библиотеку, запускается на других компьютерах, где не установлена PostgreSQL, но создать элемент невозможно, тем более отредактировать или удалить.
p
  • prod1s
  • 24 сентября 2020 г. 7:12

через QT не могу открыть файл SQLite

Вирішення знайшов. Вказав замість назви БД об'єкт класу QSqlDataBase для QSqlQuery. QSqlQuery m_query = QSqlQuery(qSqlDataBase); Після двох днів пошуку рішення, все-таки знайшов…
U

как скрыть елемент с копии виджета

Дело в том, что ui класса находится в private-секции... И из-вне доступ получить, не нарушая канонов - не получится) Можно конечно сделать что-то в духе #define private public, но это для истинн…
О нас
Услуги
© EVILEG 2015-2020
Рекомендует хостинг TIMEWEB