目录
数据信息类
数据库访问对象
数据库管理类
数据模型
搭建UI显示
在生活中做很多事情是有固定套路的,程序开发也一样。这里我介绍一下QT程序开发过程中数据库 *** 作搭配QT数据模型的常见用法,希望对你有帮助。虽然说QT提供了一些傻瓜数据模型比如QSqlTableModel、QSqlQueryModel等,方便开发者快速 *** 作和编辑数据库数据。但这些模型都有一个缺点,就是灵活性太差,如果我们需要做一个灵活性要求很高的产品项目的话,不建议使用这些数据模型。这里介绍一下自己将自定义数据模型和数据库 *** 作组合起来的一些经验,供大家参考,如果有什么不足的话,希望大家多提宝贵意见。
测试用例中我以一个消费者个人信息表为例进行说明。消费者信息表包含所有消费者的个人信息,包括:姓名、年龄、性别、身份z号。
数据信息类首先我们定义消费者信息类,用来存储每一个消费者的个人信息,定义如下:
//customer.h
#ifndef CUSTOMER_H
#define CUSTOMER_H
#include
//消费者信息类
//用来记录消费者的个人信息
class Customer
{
public:
explicit Customer(const QString& name = "");
int age() const;
void setAge(int age);
QString gender() const;
void setGender(const QString &gender);
QString iDNumber() const;
void setIDNumber(const QString &iDNumber);
int id() const;
void setId(int id);
QString name() const;
void setName(const QString &name);
private:
int mId; //消费者的ID
QString mName; //消费者的姓名
int mAge; //消费者的年龄
QString mGender; //性别
QString mIDNumber;//身份z号
};
#endif // CUSTOMER_H
//customer.cpp
#include "customer.h"
Customer::Customer(const QString &name):mId(-1),mName(name)
{}
int Customer::age() const
{
return mAge;
}
void Customer::setAge(int age)
{
mAge = age;
}
QString Customer::gender() const
{
return mGender;
}
void Customer::setGender(const QString &gender)
{
mGender = gender;
}
QString Customer::iDNumber() const
{
return mIDNumber;
}
void Customer::setIDNumber(const QString &iDNumber)
{
mIDNumber = iDNumber;
}
int Customer::id() const
{
return mId;
}
void Customer::setId(int id)
{
mId = id;
}
QString Customer::name() const
{
return mName;
}
void Customer::setName(const QString &name)
{
mName = name;
}
数据库访问对象
接下来我们定义数据库访问对象(DAO)用来访问数据库中消费者信息表中的内容,对应的实现如下:
//customerdao.h
#ifndef CUSTOMERDAO_H
#define CUSTOMERDAO_H
#include
#include
class QSqlDatabase;
class Customer;
//消费者数据表的访问对象
class CustomerDao
{
public:
CustomerDao(QSqlDatabase& database);
void init() const;
//消费者信息的增删改查
//添加一个新的消费者信息
void addCustomer(Customer& customer) const;
//更新某个消费者的个人信息
void updateCustomer(const Customer& customer) const;
//依据ID删除某个用户信息
void removeCustomer(int id) const;
//获取所有的消费者信息
std::unique_ptr>> customers() const;
private:
QSqlDatabase& mDatabase; //数据库 *** 作对象
};
#endif // CUSTOMERDAO_H
//customerdao.cpp
#include "customerdao.h"
#include "customer.h"
#include "DatabaseManager.h"
#include
#include
#include
using namespace std;
//初始化的时候将数据库 *** 作对象传递进来
CustomerDao::CustomerDao(QSqlDatabase &database):mDatabase(database)
{
}
void CustomerDao::init() const
{
//如果对应的表不存在则创建一个新表 ID作为主键
if (!mDatabase.tables().contains("customers")) {
QSqlQuery query(mDatabase);
query.exec("CREATE TABLE customers (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, "
"age INTEGER, gender TEXT, idNumber TEXT)");
//校验一下SQL语法有没有错误
DatabaseManager::debugQuery(query);
}
}
void CustomerDao::addCustomer(Customer &customer) const
{
//为了防止SQL注入,使用绑定的方式编写sql语句
QSqlQuery query(mDatabase);
query.prepare(QString("INSERT INTO customers")
+ " (name, age, gender, idNumber)"
+ " VALUES ("
+ ":name, "
+ ":age, "
":gender, "
":idNumber"
+ ")");
query.bindValue(":name", customer.name());
query.bindValue(":age",customer.age());
query.bindValue(":gender",customer.gender());
query.bindValue(":idNumber",customer.iDNumber());
query.exec();
customer.setId(query.lastInsertId().toInt());
//验证SQL语句的正确性
DatabaseManager::debugQuery(query);
}
//根据ID更新某个消费者的用户信息
void CustomerDao::updateCustomer(const Customer &customer) const
{
QSqlQuery query(mDatabase);
query.prepare(QString("UPDATE customers SET "
"name = (:name), "
"age = (:age), "
"gender = (:gender), "
"idNumber = (:idNumber) "
"WHERE id = (:id)"));
query.bindValue(":id", customer.id());
query.bindValue(":name", customer.name());
query.bindValue(":age",customer.age());
query.bindValue(":gender",customer.gender());
query.bindValue(":idNumber",customer.iDNumber());
query.exec();
DatabaseManager::debugQuery(query);
}
void CustomerDao::removeCustomer(int id) const
{
//依据ID删除某个用户的信息
QSqlQuery query(mDatabase);
query.prepare("DELETE FROM customers WHERE id = (:id)");
query.bindValue(":id", id);
query.exec();
DatabaseManager::debugQuery(query);
}
std::unique_ptr > > CustomerDao::customers() const
{
QSqlQuery query("SELECT * FROM customers", mDatabase);
query.exec();
unique_ptr>> list(new vector>());
while(query.next()) {
unique_ptr customer(new Customer());
customer->setId(query.value("id").toInt());
customer->setName(query.value("name").toString());
customer->setAge(query.value("age").toInt());
customer->setGender(query.value("gender").toString());
customer->setIDNumber(query.value("idNumber").toString());
list->push_back(move(customer));
}
return list;
}
所有的数据库访问 *** 作都在对应的数据库访问对象中进行实现,通过数据库访问对象我们就可以实现对对应的数据的增删改查了。
数据库管理类每一个数据表都有一个对应的数据库访问对象,针对数据库本身和数据库访问对象我们也需要进行管理。这时候就引入一个数据库管理类了,它可以对数据库类型、数据库账号密码等内容进行管理,也可以对数据库访问对象进行管理,实现如下:
//DatabaseManager.h
#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H
#include
#include
#include "customerdao.h"
class QSqlQuery;
class QSqlDatabase;
//数据库的名称
const QString DATABASE_FILENAME = "Database.db";
//数据库的管理者负责管理数据库的相关信息
class DatabaseManager
{
public:
//对SQL语句的正确性进行校验
static void debugQuery(const QSqlQuery& query);
//数据库管理者的单例模式
static DatabaseManager& instance();
~DatabaseManager();
protected:
DatabaseManager(const QString& path = DATABASE_FILENAME);
DatabaseManager& operator=(const DatabaseManager& rhs);
private:
std::unique_ptr mDatabase;
public:
const CustomerDao customerDao;
};
#endif // DATABASEMANAGER_H
//DatabaseManager.cpp
#include "DatabaseManager.h"
#include
#include
#include
#include
#include
#include
void DatabaseManager::debugQuery(const QSqlQuery& query)
{
if (query.lastError().type() == QSqlError::ErrorType::NoError) {
qDebug() << "Query OK:" << query.lastQuery();
} else {
qWarning() << "Query KO:" << query.lastError().text();
qWarning() << "Query text:" << query.lastQuery();
}
}
DatabaseManager& DatabaseManager::instance()
{
static DatabaseManager singleton;
return singleton;
}
DatabaseManager::DatabaseManager(const QString& path) :
mDatabase(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"))),
customerDao(*mDatabase)
{
//构造的时候打开数据库
mDatabase->setDatabaseName(path);
bool openStatus = mDatabase->open();
qDebug() << "Database connection: " << (openStatus ? "OK" : "Error");
customerDao.init();
}
DatabaseManager::~DatabaseManager()
{
mDatabase->close();
}
数据模型
数据库 *** 作类完成之后,我们就可以实现数据模型和数据表信息字段的关联了。这里我们通过实现一个TableModel将数据库中的表内容以表格的形式显示出来。数据模型的实现如下:
//customermodel.h
#ifndef PICTUREMODEL_H
#define PICTUREMODEL_H
#include
#include
#include
#include "DatabaseManager.h"
#include "customer.h"
class DatabaseManager;
class CustomerModel : public QAbstractTableModel
{
Q_OBJECT
public:
CustomerModel(QObject* parent = 0);
//添加新消费者信息
QModelIndex addCustomer(const Customer& customer);
//行列数
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent) const;
//设置和读取数据
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
//删除行
Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
QHash roleNames() const override;
//设置表单元的属性
Qt::ItemFlags flags(const QModelIndex &index) const;
private:
bool isIndexValid(const QModelIndex& index) const;
private:
DatabaseManager& mDb; //数据库管理类
//数据库中的表内容
std::unique_ptr>> mCustomers;
};
#endif // PICTUREMODEL_H
//customermodel.cpp
#include "CustomerModel.h"
#include "DatabaseManager.h"
#include "customerdao.h"
using namespace std;
CustomerModel::CustomerModel(QObject* parent) :
QAbstractTableModel(parent),
mDb(DatabaseManager::instance()),
mCustomers(mDb.customerDao.customers())
{
}
QModelIndex CustomerModel::addCustomer(const Customer& customer)
{
int rowIndex = rowCount();
beginInsertRows(QModelIndex(), rowIndex, rowIndex);
unique_ptr newCustomer(new Customer(customer));
mDb.customerDao.addCustomer(*newCustomer);
mCustomers->push_back(move(newCustomer));
endInsertRows();
return index(rowIndex, 0);
}
int CustomerModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return mCustomers->size();
}
int CustomerModel::columnCount(const QModelIndex &parent) const
{
return 4;
}
QVariant CustomerModel::data(const QModelIndex& index, int role) const
{
if (!isIndexValid(index)) {
return QVariant();
}
if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();
const Customer& customer = *mCustomers->at(index.row());
int column = index.column();
if(column == 0)
{
return customer.name();
}
else if(column == 1)
{
return customer.age();
}
else if(column == 2)
{
return customer.gender();
}
else if(column == 3)
{
return customer.iDNumber();
}
}
bool CustomerModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (!isIndexValid(index)) {
return false;
}
Customer& customer = *mCustomers->at(index.row());
int column = index.column();
if(column == 0)
{
customer.setName(value.toString());
}
else if(column == 1)
{
customer.setAge(value.toInt());
}
else if(column == 2)
{
customer.setGender(value.toString());
}
else if(column == 3)
{
customer.setIDNumber(value.toString());
}
mDb.customerDao.updateCustomer(customer);
emit dataChanged(index, index);
return true;
}
bool CustomerModel::removeRows(int row, int count, const QModelIndex& parent)
{
if (row < 0
|| row >= rowCount()
|| count < 0
|| (row + count) > rowCount()) {
return false;
}
beginRemoveRows(parent, row, row + count - 1);
int countLeft = count;
while (countLeft--) {
const Customer& customer = *mCustomers->at(row + countLeft);
mDb.customerDao.removeCustomer(customer.id());
}
mCustomers->erase(mCustomers->begin() + row,
mCustomers->begin() + row + count);
endRemoveRows();
return true;
}
QHash CustomerModel::roleNames() const
{
QHash roles;
roles[0] = "name";
roles[1] = "age";
roles[2] = "gender";
roles[3] = "idNumber";
return roles;
}
Qt::ItemFlags CustomerModel::flags(const QModelIndex &index) const
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}
bool CustomerModel::isIndexValid(const QModelIndex& index) const
{
if (index.row() < 0
|| index.row() >= rowCount()
|| !index.isValid()) {
return false;
}
return true;
}
将数据库中的字段和模型绑定之后,我们就可以通过模型来 *** 作数据库中的信息了,非常方便吧。
下面我们搭建一个简单的UI来测试一下数据库信息的绑定。
搭建UI显示UI显示效果如下,左边TableView显示数据表内容,右边按钮来动态的添加用户信息删除用户信息。
对应的实现逻辑如下:
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include "customermodel.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
//添加测试用户
void slot_add_new_customer();
//删除最后一个添加的用户
void slot_delete_customer();
private:
Ui::MainWindow *ui;
CustomerModel* mCustomerModel;
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "customermodel.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mCustomerModel = new CustomerModel();
ui->tableView->setModel(mCustomerModel);
connect(ui->addCustomerBtn,SIGNAL(clicked(bool)),this,SLOT(slot_add_new_customer()));
connect(ui->deleteCustomerBtn,SIGNAL(clicked(bool)),this,SLOT(slot_delete_customer()));
}
MainWindow::~MainWindow()
{
delete ui;
}
//添加测试用户
void MainWindow::slot_add_new_customer()
{
Customer customer;
customer.setAge(18);
customer.setGender("女");
customer.setName("小红");
customer.setIDNumber("13031220201212009**");
mCustomerModel->addCustomer(customer);
}
//删除最后一个添加的用户
void MainWindow::slot_delete_customer()
{
int rowCount = mCustomerModel->rowCount();
mCustomerModel->removeRows(rowCount-1,1);
}
如果感兴趣的,可以参考对应的源码,下载地址如下:
链接:https://pan.baidu.com/s/125SRIguWFnQHqlGnn71Scg
提取码:p1m8
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)