Evgenii Legotckoi
Evgenii LegotckoiNov. 24, 2015, 9:11 a.m.

QML - Lesson 016. SQLite database and the working with it in QML Qt

A small example to work with the database in QML Qt. This lesson brings together information on the use of signals and slots in the Qt QML , access to C++ classes from QML layer implementation of the application interface on QML, as well as the implementation of the model/view for the database tables.

The database contains a table with a list of people, which has four columns:

  • id (INTEGER) - a unique record number;
  • FirstName (VARCHAR (255)) - First Name;
  • SurName (VARCHAR (255)) - Last Name;
  • Nik (VARCHAR (255)) - Nik name.

The application must implement removing and adding records to the database through the application interface. To add records to the database three fields for data entry will be used and a button that initiates the addition of data to an SQL database. Adding entries to the table through a wrapper class designed for this application is present in metodom.Takzhe ListModel class that implements the model of data representation for the information display in the TableView in QML layer.


Project structure

  • QmlDataBase.pro - the profile of the project;
  • database.h - wrapper class header file to work with the database;
  • database.cpp - file source wrapper class codes for the work with the database;
  • listmodel.h - header data model file;
  • listmodel.cpp - file source data model;
  • main.cpp - the main file of the application source code;
  • main.qml - basic qml file.

QmlDataBase.pro

To work with the database you need to connect sql module, as well as widgets module for native application appearance.

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

Basically, source files are included wrapper classes to work with the database and data model class. Objects of these classes must be declared and initialized in the file, and configure access to these objects and their properties of QML layer.

Once access to the objects set of QML layer become available following object properties and functions are declared in its class as:

  1. Signals
  2. Slots
  3. As well as the functions that appear in the macro 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();

    engine.rootContext()->setContextProperty("myModel", model);
    engine.rootContext()->setContextProperty("database", &database);

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

    return app.exec();
}

database.h

In this class, declared methods for working with the database:

  • methods to connect to the database, restore it;
  • methods for adding records to the database;
  • methods for deleting entries in the data table.

Connecting to a database is necessary for the proper operation of the data model that inherit from QSqlQueryModel . And, accordingly, it uses SQL queries to open in the database application.

This class implements the Facade design pattern, although not completely, because as I said, that one of QSqlQueryModel entities used in the data model in this lesson.

ATTENTION!!! - The database file is created in the folder C:/example , so the correct method or DataBase::connectToDataBase() example or create a folder on drive 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"              

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);      // Adding entries to the table
    bool inserIntoTable(const QString &fname, const QString &sname, const QString &nik);
    bool removeRecord(const int id); // Removing records from the table on its id
};

#endif // DATABASE_H

database.cpp

Initialize the database connection is made by connectToDataBase() . The name of the table, database, file, and columns in the table specified in the directives define in the header file.

#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() << "Failed to restore the database";
        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()
{
    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)
{
    QSqlQuery query;
    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());

    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)
{
    QSqlQuery query;

    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

The data model is a class inherited from QSqlQueryModel , which override the data() and roleNames() . Also listed in the class of the role in which information is transmitted in the representation in the interface. To delete data, you must obtain a unique record ID, which extends from the model by the method of getID() on the role and line number that was passed from view. To retrieve data from databases used updateModel() method, which established SQL-query the database.

#ifndef LISTMODEL_H
#define LISTMODEL_H

#include <QObject>
#include <QSqlQueryModel>

class ListModel : public QSqlQueryModel
{
    Q_OBJECT
public:
    /* We list all the roles that will be used in the TableView. 
     * As you can see, they have to be in the memory above the parameter Qt::UserRole. 
     * Due to the fact that the information below this address is not for customizations
     * */
    enum Roles {
        IdRole = Qt::UserRole + 1,      // id
        FNameRole,                      // Firt name
        SNameRole,                      // Last name
        NikRole                         // Nik name
    };

    explicit ListModel(QObject *parent = 0);

    // Override the method that will return the data
    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

protected:
    /* hashed table of roles for speakers. 
     * The method used in the wilds of the base class QAbstractItemModel, 
     * from which inherits the class QSqlQueryModel
     * */
    QHash<int, QByteArray> roleNames() const;

signals:

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

#endif // LISTMODEL_H

listmodel.cpp

For the implementation of the model in a file source connect the header file database.h , which features define directive for the names of tables and columns. Return data is performed on predefined roles, which must be identical in the TableView , which will be used to display data.

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

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

// The method for obtaining data from the model
QVariant ListModel::data(const QModelIndex & index, int role) const {

    // Define the column number, on the role of number
    int columnId = role - Qt::UserRole - 1;
    // Create the index using a column ID
    QModelIndex modelIndex = this->index(index.row(), columnId);

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

// The method updates the tables in the data model representation
void ListModel::updateModel()
{
    // The update is performed SQL-queries to the database
    this->setQuery("SELECT id, " TABLE_FNAME ", " TABLE_SNAME ", " TABLE_NIK " FROM " TABLE);
}

// Getting the id of the row in the data view model
int ListModel::getId(int row)
{
    return this->data(this->index(row, 0), IdRole).toInt();
}

main.qml

In Qt Model / View / Controller paradigm change in the model / view . Presentation combines a controller and a view. Thus, main.qml processes the information that the user enters and passes it to the backend in a digestible form, but when you consider that the object class is given database access layer of QML, and the addition of data is made through the function slot, it can be roughly assumed that the the controller is implemented in the view.

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")

    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("Add")

            // Make a new entry in the database
            onClicked: {
                database.inserIntoTable(fnameField.text , snameField.text, nikField.text)
                myModel.updateModel() // And updates the data model with a new record
            }
        }
    }

    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: "First Name"
        }
        TableViewColumn {
            role: "sname"
            title: "Last name"
        }
        TableViewColumn {
            role: "nik"
            title: "Nik name"
        }

        model: myModel

        // Setting lines in TableView to intercept mouse left click
        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() // Call the context menu
                        break
                    default:
                        break
                    }
                }
            }
        }
    }

    // The context menu offers deleting a row from the database
    Menu {
        id: contextMenu

        MenuItem {
            text: qsTr("Remove")
            onTriggered: {
                /* Call the dialog box that will clarify the intention to remove the row from the database
                 * */
                dialogDelete.open()
            }
        }
    }

    // Dialog of confirmation the removal line from the database
    MessageDialog {
        id: dialogDelete
        title: qsTr("Remove record")
        text: qsTr("Confirm the deletion of log entries")
        icon: StandardIcon.Warning
        standardButtons: StandardButton.Ok | StandardButton.Cancel

        // If the answer ...
        onAccepted: {
            /* ... remove the line by id, which is taken from the data model 
             * on the line number in the presentation
             * */
            database.removeRecord(myModel.getId(tableView.currentRow))
            myModel.updateModel(); 
        }
    }
}

Conclusion

As a result, you get an application that will appear as shown in the following figure.

In addition, I recommend reading more about Facade design pattern and see a more complete embodiment of this pattern in the following article: "Design pattern "Facade"

Video

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Terabaytus
  • June 5, 2018, 7:01 a.m.
Добрый день, запустил ваш пример при нажатии на кнопку получаю вот эту ошибку

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

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

Добрый день, пытаюсь передать текст из 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);
}
Evgenii Legotckoi
  • June 18, 2018, 3:01 a.m.

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

ММ
  • May 1, 2020, 5:44 a.m.

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

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

D:
  • Aug. 6, 2020, 9:14 a.m.
  • (edited)

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

РГ
  • Aug. 10, 2020, 9:33 a.m.
  • (edited)

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

Evgenii Legotckoi
  • Aug. 20, 2020, 6:13 a.m.

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

ВР
  • Nov. 17, 2020, 3:31 p.m.

Помогите, пожалуйста. У меня похожая задача, но я в qml слой долен передать не чистый запрос, а со сложной обработкой, поэтому у меня в С++ слое есть иерархия классов, которая имитирует бд и заполняется при включении приложения, но после того, как там всё посчитается, мне нужно отобразить это в qml слое и тут я сломался. Никак не могу понять, как я могу из плюсового слоя наплодить элементов list view в qml слое? Выходит, мне из плюсового слоя нужно как-то заполнять делегат qml слоя и отображать его. Вообще не могу вшарить, как это происходит.

juvf
  • March 6, 2023, 2:44 a.m.

Добрый день. Я тоже присоеденяюсь к вопросу:
[s]"Второй вопрос : как ваш класс listmodel связывается с бд, т.е. каким образом он понимает , что она существует. проштудировал ваш пример и нигде нет ни ссылки ни намека на класс database, кроме подключения хедера. При попытке воспроизвести ваш класч listview в методе update в дебаге выдает сообщение о том что не удалось открыть бд. Заранее спасибо"[/s]

Evgenii Legotckoi
  • March 13, 2023, 8:13 a.m.

Смотрите, QSqlDatabase имеет статический метод addDatabase("QSQLITE"), который создаёт соединение с базой данных и возвращает инстанс базы данных

QSqlDatabase dbase = QSqlDatabase::addDatabase("QSQLITE");

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

А сама инициализация этого подключения в данном кода выполняется в файле main.cpp

#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();
}

Comments

Only authorized users can post comments.
Please, Log in or Sign up
г
  • ги
  • April 23, 2024, 3:51 p.m.

C++ - Test 005. Structures and Classes

  • Result:41points,
  • Rating points-8
l
  • laei
  • April 23, 2024, 9:19 a.m.

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:10points,
  • Rating points-10
l
  • laei
  • April 23, 2024, 9:17 a.m.

C++ - Тест 003. Условия и циклы

  • Result:50points,
  • Rating points-4
Last comments
k
kmssrFeb. 8, 2024, 6:43 p.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 10:30 a.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 8:38 a.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 18, 2023, 9:01 p.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
G
GarApril 22, 2024, 5:46 a.m.
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil AcademicsApril 20, 2024, 7:45 a.m.
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasovApril 14, 2024, 6:41 a.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел ДорофеевApril 14, 2024, 2:35 a.m.
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrexApril 4, 2024, 4:47 a.m.
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Follow us in social networks