У меня есть просмотр списка во внешнем интерфейсе, в котором есть тексты для отображения firstname
, lastname
, city
и ... плюс элемент флажка для каждой записи.
Я хочу связать этот флажок элемент к полю selected
в базе данных, который имеет тип INTEGER
.
Проблема в том, что я не знаю, как привязать элемент флажка к selected
полю данных в базе данных SQLite!
Для отображения текстов в интерфейсе QML просто я использовал текстовый элемент со свойством text, для которого установлено правильное значение roleid, например, text: firstname
или text: lastname
... Но если я сделаю нечто подобное для элемента флажка, я получу привязку l oop и программа стремится к sh!
Нужно ли мне переопределить функцию setData?
Может ли кто-нибудь указать мне правильное направление?
Вот пример:
database.h:
#ifndef Database_H
#define Database_H
#include <QObject>
#include <QSql>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlDatabase>
#include <QFile>
#include <QDate>
#include <QDebug>
class Database : public QObject
{
Q_OBJECT
public:
explicit Database(QObject *parent = nullptr);
~Database();
void connectToDatabase();
private:
QSqlDatabase db;
private:
bool openDatabase();
bool restoreDatabase();
void closeDatabase();
bool createTable();
public slots:
bool inserIntoTable(const QStringList &data); // Adding entries to the table
bool modifyTable(int id, bool selection);
bool removeRecord(int id); // Removing records from the table on its id
};
#endif // Database_H
database. cpp:
#include "database.h"
#include "DatabaseColumns.h"
Database::Database(QObject *parent) : QObject(parent){}
Database::~Database(){}
void Database::connectToDatabase()
{
!QFile{DATABASE_NAME}.exists() ? this->restoreDatabase() : this->openDatabase();
}
bool Database::restoreDatabase()
{
if(this->openDatabase()){
return (this->createTable()) ? true : false;
} else {
qDebug() << "Failed to restore the Database";
return false;
}
}
bool Database::openDatabase()
{
db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName(DATABASE_HOSTNAME);
db.setDatabaseName(DATABASE_NAME);
if(db.open()){
return true;
}
return false;
}
void Database::closeDatabase()
{
db.close();
}
bool Database::createTable()
{
QString str;
int counter = 0;
for (const QString& tempStr: DATABASE_COLUMNS){
switch (counter) {
case 0:
str += tempStr + " " + DATABASE_ID_TYPE ", ";
break;
case 1:
str += tempStr + " " + DATABASE_CHECKED_TYPE ", ";
break;
case DATABASE_LENGTH - 1:
str += tempStr + " VARCHAR(255) NOT NULL";
break;
default:
str += tempStr + " VARCHAR(255) NOT NULL, ";
}
++counter;
}
QSqlQuery query;
if(!query.exec( "CREATE TABLE " TABLE " (" + str + ")"))
{
qDebug() << "Database: error of create " << TABLE;
qDebug() << query.lastError().text();
return false;
}
return true;
}
bool Database::inserIntoTable(const QStringList &data)
{
QSqlQuery query; QString str{"INSERT INTO " TABLE " ("};
int counter = 0;
for (const QString& tempStr: DATABASE_COLUMNS)
{
switch (counter)
{
case 0:
break;
case DATABASE_LENGTH - 1:
str += tempStr;
break;
default:
str += tempStr + ", ";
}
++counter;
}
str += ") VALUES (";
counter = 0;
for (const QString& tempStr: DATABASE_COLUMNS)
{
switch (counter)
{
case 0:
break;
case DATABASE_LENGTH - 1:
str += ":" + tempStr + ")";
break;
default:
str += ":" + tempStr + ", ";
}
++counter;
}
query.prepare(str);
counter = 0;
for (const QString& tempStr: DATABASE_COLUMNS)
{
if (tempStr != "id") {
query.bindValue(":" + tempStr, data[counter]);
++counter;
}
}
if(!query.exec())
{
qDebug() << "error insert into " << TABLE;
qDebug() << query.lastError().text();
return false;
}
return true;
}
bool Database::modifyTable(int id, bool selection)
{
QSqlQuery query;
if(!query.exec("UPDATE " TABLE " SET selected = " + QString::number(selection) + " WHERE id = " + QString::number(id)))
{
qDebug() << "error delete row " << TABLE;
qDebug() << query.lastError().text();
return false;
}
return true;
}
bool Database::removeRecord(int id)
{
QSqlQuery query;
if(!query.exec("DELETE FROM " TABLE " WHERE id = " + QString::number(id)))
{
qDebug() << "error delete row " << TABLE;
qDebug() << query.lastError().text();
return false;
} else {
return true;
}
}
DatabaseColumns.h:
#ifndef DATABASECOLUMNS_H
#define DATABASECOLUMNS_H
#include <array>
#include <QString>
#define DATABASE_HOSTNAME "localhost"
#define DATABASE_NAME "mydatabase.db"
#define TABLE "MyTable"
#define DATABASE_LENGTH 3
#define DATABASE_ID_TYPE "INTEGER PRIMARY KEY AUTOINCREMENT"
#define DATABASE_CHECKED_TYPE "INTEGER"
#define DATABASE_COLUMNS std::array<QString, DATABASE_LENGTH>{\
"id",\
"selected",\
"firstname"}
#endif // DATABASECOLUMNS_H
listmodel.h:
#ifndef LISTMODEL_H
#define LISTMODEL_H
#include <QObject>
#include <QSqlQueryModel>
class ListModel : public QSqlQueryModel
{
Q_OBJECT
public:
explicit ListModel(QObject *parent = nullptr);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
protected:
QHash<int, QByteArray> roleNames() const override;
signals:
public slots:
void updateModel();
int getId(int row);
};
#endif // LISTMODEL_H
listmodel. cpp:
#include "listmodel.h"
#include "DatabaseColumns.h"
#include <QtDebug>
#include <QSqlError>
ListModel::ListModel(QObject *parent) :
QSqlQueryModel(parent)
{
updateModel();
}
QVariant ListModel::data(const QModelIndex &inputIndex, int role) const {
int columnId = role - Qt::UserRole - 1;
QModelIndex modelIndex = index(inputIndex.row(), columnId);
return QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
}
QHash<int, QByteArray> ListModel::roleNames() const {
QHash<int, QByteArray> roles;
int i = Qt::UserRole + 1;
for(const QString& str: DATABASE_COLUMNS){
roles[i] = str.toUtf8();
++i;
}
return roles;
}
void ListModel::updateModel()
{
QString str; int counter = 0;
for(const QString& tempStr: DATABASE_COLUMNS){
if (counter != DATABASE_LENGTH - 1)
str += tempStr + ", ";
else str += tempStr;
++counter;
}
setQuery("SELECT " + str + " FROM " TABLE);
}
int ListModel::getId(int row)
{
return data(index(row, 0), Qt::UserRole + 1).toInt();
}
main.qml:
import QtQuick 2.14
import QtQuick.Controls 2.14
ApplicationWindow {
id: window
visible: true
minimumWidth: 800
minimumHeight: 600
TextField{
id: name
anchors.bottom: acceptKey.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.margins: 100
placeholderText: "input the name"
}
Button{
id: acceptKey
text: "Accept"
anchors.centerIn: parent
onClicked: {
database.inserIntoTable([false, name.text])
myModel.updateModel()
}
}
ListView {
id: tableView
clip: true
anchors.top: acceptKey.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: 300
height: width
property int textWidth: 100
contentWidth: contentItem.childrenRect.width
contentHeight: contentItem.childrenRect.height
headerPositioning: ListView.OverlayHeader
flickableDirection: Flickable.HorizontalAndVerticalFlick
highlight: Rectangle {
color: "Blue"
opacity: 0.2
}
header: Rectangle {
property alias checkState: headerCheckBox.checkState
height: tableHead.implicitHeight + seperator.height
width: tableHead.implicitWidth
z: 2
Row {
id: tableHead
spacing: 100
layoutDirection: Qt.RightToLeft
CheckBox {id: headerCheckBox; indicator.width: 20; indicator.height: 20}
Text {width: 50; text: "Name" }
}
ToolSeparator {
id: seperator
height: 7
padding: 0
topPadding: 0
bottomPadding: 0
anchors { top: tableHead.bottom; right: parent.right }
orientation: Qt.Horizontal
width: tableHead.implicitWidth
}
}
model: myModel
delegate: Item{
width: parent.width
height: rowId.implicitHeight
MouseArea{
anchors.fill: parent
onClicked: tableView.currentIndex = index
}
Row {
id: rowId
spacing: 100
layoutDirection: Qt.RightToLeft
CheckBox {
id: checkBox
indicator.width: 20; indicator.height: 20
onCheckStateChanged: {
if (checkState === Qt.Checked){
console.log("Currently checked!")
database.modifyTable(myModel.getId(tableView.currentIndex), true)
}else{
console.log("Unchecked!")
database.modifyTable(myModel.getId(tableView.currentIndex), false)
}
myModel.updateModel()
}
}
Text {
width: 50
text: firstname
}
}
}
}
}
и, наконец, main. cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include "database.h"
#include "listmodel.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Database database;
database.connectToDatabase();
ListModel model;
engine.rootContext()->setContextProperty("myModel", &model);
engine.rootContext()->setContextProperty("database", &database);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
Проба лем, когда я выбираю флажок foreach record, они не включаются и остаются навсегда!