使用-QML-和-QtSql-实现-SQLite-数据库操作
目录
使用 QML 和 QtSql 实现 SQLite 数据库操作
文章目录
前言
在现代应用程序开发中,数据库操作是不可或缺的一部分。Qt 提供了强大的 QtSql 模块,可以轻松地与 SQLite 数据库进行交互。本文将详细介绍如何使用 QML 和 C++ 后端实现 SQLite 数据库的增删改查(CRUD)操作。
一、 项目结构
项目的文件结构如下:
qml_SQLite_demo1/
├── database.h
├── database.cpp
├── main.cpp
├── main.qml
├── qml.qrc
└── sqlite_crud.pro
二、配置 .pro 文件
首先,在 .pro 文件中启用 Sql 模块,并配置项目的基本信息。
TEMPLATE = app
QT += qml quick widgets core gui sql
CONFIG += c++17
SOURCES += main.cpp database.cpp
HEADERS += database.h
RESOURCES += qml.qrc
三、创建 Database 类
Database 类负责处理数据库的打开、关闭以及增删改查操作。
3.1 database.h
#ifndef DATABASE_H
#define DATABASE_H
#include <QObject>
#include <QSqlDatabase>
#include <QVariantList>
class Database : public QObject
{
Q_OBJECT
public:
explicit Database(QObject *parent = nullptr);
~Database();
Q_INVOKABLE bool openDatabase(const QString &path);
Q_INVOKABLE QVariantList executeQuery(const QString &query, const QVariantList ¶ms = QVariantList());
Q_INVOKABLE bool executeNonQuery(const QString &query, const QVariantList ¶ms = QVariantList());
private:
QSqlDatabase db;
};
#endif // DATABASE_H
3.2 database.cpp
#include "database.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlRecord>
#include <QDebug>
Database::Database(QObject *parent) : QObject(parent)
{
}
Database::~Database()
{
if (db.isOpen()) {
db.close();
}
}
bool Database::openDatabase(const QString &path)
{
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
if (!db.open()) {
qWarning() << "Failed to open database:" << db.lastError().text();
return false;
}
return true;
}
QVariantList Database::executeQuery(const QString &query, const QVariantList ¶ms)
{
QVariantList result;
QSqlQuery sqlQuery;
sqlQuery.prepare(query);
for (const QVariant ¶m : params) {
sqlQuery.addBindValue(param);
}
if (sqlQuery.exec()) {
while (sqlQuery.next()) {
QVariantMap row;
for (int i = 0; i < sqlQuery.record().count(); i++) {
row[sqlQuery.record().fieldName(i)] = sqlQuery.value(i);
}
result.append(row);
}
} else {
qWarning() << "Query failed:" << sqlQuery.lastError().text();
}
return result;
}
bool Database::executeNonQuery(const QString &query, const QVariantList ¶ms)
{
QSqlQuery sqlQuery;
sqlQuery.prepare(query);
for (const QVariant ¶m : params) {
sqlQuery.addBindValue(param);
}
if (!sqlQuery.exec()) {
qWarning() << "Query failed:" << sqlQuery.lastError().text();
return false;
}
return true;
}
四、main.cpp
在 main.cpp 中,我们将 Database 类注册到 QML 中,并初始化数据库。
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "database.h"
#include <QDir>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// 创建 Database 对象
Database database;
// 将 Database 对象注册到 QML 中
engine.rootContext()->setContextProperty("database", &database);
// 设置数据库文件路径
QString dbPath = QDir::currentPath() + "/MyDatabase.db";
qDebug() << "Database path:" << dbPath; // 打印数据库文件路径
// 打开数据库
if (!database.openDatabase(dbPath)) {
qWarning() << "Failed to open database!";
return -1;
}
// 加载 QML 文件
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();
}
五、编写 QML 界面
在 main.qml 中,我们设计一个简单的界面,用于展示数据并实现增删改查操作。
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
ApplicationWindow {
visible: true
width: 800
height: 600
title: "SQLite CRUD Example"
// 数据模型
ListModel {
id: dataModel
}
ColumnLayout {
anchors.fill: parent
spacing: 10
anchors.margins: 20
// 操作按钮
RowLayout {
spacing: 10
Button {
text: "添加"
onClicked: addDialog.open()
}
Button {
text: "修改"
enabled: listView.currentIndex >= 0
onClicked: editDialog.open()
}
Button {
text: "删除"
enabled: listView.currentIndex >= 0
onClicked: deleteItem()
}
Button {
text: "刷新"
onClicked: loadData()
}
}
// 表头
Row {
spacing: 0
Repeater {
model: ["ID", "姓名", "年龄"]
Rectangle {
width: [100, 200, 100][index]
height: 30
color: "#f0f0f0"
Text {
text: modelData
anchors.centerIn: parent
font.bold: true
}
}
}
}
// 数据表格
ListView {
id: listView
model: dataModel
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 1
clip: true
delegate: Rectangle {
width: listView.width
height: 30
color: ListView.isCurrentItem ? "#d3d3d3" : "white"
Row {
spacing: 0
Rectangle {
width: 100
height: 30
color: "transparent"
Text {
text: modelData.id
anchors.centerIn: parent
}
}
Rectangle {
width: 200
height: 30
color: "transparent"
Text {
text: modelData.name
anchors.centerIn: parent
}
}
Rectangle {
width: 100
height: 30
color: "transparent"
Text {
text: modelData.age
anchors.centerIn: parent
}
}
}
}
}
}
// 添加对话框
Dialog {
id: addDialog
title: "添加数据"
width: 400
height: 200
ColumnLayout {
anchors.fill: parent
spacing: 10
TextField {
id: addNameField
placeholderText: "请输入姓名"
Layout.fillWidth: true
}
TextField {
id: addAgeField
placeholderText: "请输入年龄"
Layout.fillWidth: true
}
RowLayout {
Button {
text: "取消"
onClicked: addDialog.close()
}
Button {
text: "确定"
onClicked: {
database.executeNonQuery("INSERT INTO People (name, age) VALUES (?, ?)", [addNameField.text, parseInt(addAgeField.text)]);
loadData();
addDialog.close();
}
}
}
}
}
// 修改对话框
Dialog {
id: editDialog
title: "修改数据"
width: 400
height: 200
property var currentItem: null
ColumnLayout {
anchors.fill: parent
spacing: 10
TextField {
id: editNameField
placeholderText: "请输入姓名"
text: editDialog.currentItem ? editDialog.currentItem.name : ""
Layout.fillWidth: true
}
TextField {
id: editAgeField
placeholderText: "请输入年龄"
text: editDialog.currentItem ? editDialog.currentItem.age : ""
Layout.fillWidth: true
}
RowLayout {
Button {
text: "取消"
onClicked: editDialog.close()
}
Button {
text: "确定"
onClicked: {
database.executeNonQuery("UPDATE People SET name = ?, age = ? WHERE id = ?", [editNameField.text, parseInt(editAgeField.text), editDialog.currentItem.id]);
loadData();
editDialog.close();
}
}
}
}
}
// 加载数据
function loadData() {
var data = database.executeQuery("SELECT * FROM People");
dataModel.clear();
data.forEach(function(item) {
dataModel.append(item);
});
}
// 删除数据
function deleteItem() {
var item = dataModel.get(listView.currentIndex);
database.executeNonQuery("DELETE FROM People WHERE id = ?", [item.id]);
loadData();
}
// 初始化
Component.onCompleted: {
database.executeNonQuery("CREATE TABLE IF NOT EXISTS People (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)");
loadData();
}
}
六、实验现象
在运行程序后,将在项目文件夹下创建.db数据库文件,并且可以在QML界面中实现对数据库的增删改查: