Qt实战笔记-从零开始搭建一套库存管理系统-(五)使用QSqlTableModel实现数据的增删改查

上一章节我们已经通过用户注册和登录功能初步接触了数据库,主要是通过QSqlQuery来与数据库进行交互,这种方式呢有一定局限性,需要比较懂sql语句,而且调用起来比较麻烦。下面我们通过使用QSqlTableModel来和数据库交互,QSqlTableModel是一个Qt封装好的数据库模型类,关联好数据库和数据表之后,我们只需要和它打交道就可以操控数据库啦。

目录

1、创建数据表

2、构建UI

3、增加数据

4、查询数据

5、修改数据

6、删除数据

7、总结


1、创建数据表

现在数据库中只有一个简单的用户表,用来记录用户数据,我们接下来向数据库中添加其他数据表,用来记录供应商信息、商品信息等。

创建表格之前还是先设计表结构,下面是我设计的商家表和商品表的表结构,当然,你可以按照自己的实际情况去设计,这里只是一个示例。表结构一般也会随着开发过程不断调整,但最好是在开始能设计的合理一些,减少一些不必要的调整。

供应商信息表的表结构设计如下:

列名称 类型 长度 说明
ID 整数 - 商家ID
name 字符 30 商家名称
add 字符 30 商家所在地
date 字符 30 添加日期
category 字符 30 经营类目
goodsCount 整数 - 商品数量
contact 字符 30 联系人
telephone 字符 30 联系方式

商品信息表的表结构设计如下:

列名称 类型 长度 说明
ID 整数 - 商品ID
name 字符 30 商品名称
category 字符 30 所属类目
speci 字符 30 商品规格
addr 字符 30 商品产地
brand 字符 30 商品品牌
manu 字符 30 制造商
note 字符 30 备注

我们在mySqlite中的creatTable()中增加创建其他表格的语句,如下:

bool mySqlite::createTable()
{
    query=new QSqlQuery;
    QString userStr = "create table if not exists user("
                      "[id] integer primary key autoincrement,"
                      "[name] varchar(30),"
                      "[password] varchar(30),"
                      "[role] varchar(30)"
                      ")";
    QString supplierStr = "create table if not exists supplier("
                          "[id] integer primary key autoincrement,"
                          "[name] varchar(30),"
                          "[addr] varchar(30),"
                          "[date] varchar(30),"
                          "[category] varchar(30),"
                          "[goodsCount] integer,"
                          "[contact] varchar(30),"
                          "[telephone] varchar(30)"
                          ")";
    QString goodsStr = "create table if not exists goods("
                       "[id] integer primary key autoincrement,"
                       "[name] varchar(30),"
                       "[category] varchar(30),"
                       "[speci] varchar(30),"
                       "[addr] varchar(30),"
                       "[brand] varchar(30),"
                       "[manu] varchar(30),"
                       "[note] varchar(30)"
                       ")";
    if(!(query->exec(userStr)&&query->exec(supplierStr)&&query->exec(goodsStr)))
        return false;
    return true;
}

运行之后,用sqliteman查看之后,可以看到数据库中已经添加好了这两张表。

2、构建UI

接下来我们在supplier和goods两个页签中补充完整的内容。

首先,我们在mainwindow头文件中声明一个QSqlTableModel* supplierModel,再增加一个函数,就叫creatSupplierPage()吧,返回类型为QWidget,函数体内容如下:

QWidget *MainWindow::creatSupplierPage()
{
    QWidget *supplierPage = new QWidget;

    QLabel *titleLabel = new QLabel("供应商信息");
    QPushButton *addButton = new QPushButton("添加");
    QHBoxLayout *titleLayout = new QHBoxLayout;
    titleLayout->addWidget(titleLabel);
    titleLayout->addStretch();
    titleLayout->addWidget(addButton);

    QLabel *idLabel = new QLabel("商家编号");
    QLineEdit *idEdit = new QLineEdit;
    QLabel *nameLabel = new QLabel("商家名称");
    QLineEdit *nameEdit = new QLineEdit;
    QLabel *addrLabel = new QLabel("所在地");
    QComboBox *addrEdit = new QComboBox;
    QLabel *dateLabel = new QLabel("添加日期");
    QDateEdit *dateEdit = new QDateEdit;
    QLabel *cateLabel = new QLabel("经营品类");
    QComboBox *cateEdit = new QComboBox;
    QPushButton *searchButton = new QPushButton("搜索");

    QHBoxLayout *sLayout_1 = new QHBoxLayout;
    sLayout_1->addWidget(idLabel);
    sLayout_1->addWidget(idEdit);
    sLayout_1->addStretch();
    sLayout_1->addWidget(nameLabel);
    sLayout_1->addWidget(nameEdit);
    sLayout_1->addStretch();
    sLayout_1->addWidget(addrLabel);
    sLayout_1->addWidget(addrEdit);
    sLayout_1->addStretch();
    sLayout_1->addWidget(dateLabel);
    sLayout_1->addWidget(dateEdit);

    QHBoxLayout *sLayout_2 = new QHBoxLayout;
    sLayout_2->addWidget(cateLabel);
    sLayout_2->addWidget(cateEdit);
    sLayout_2->addStretch();
    sLayout_2->addWidget(searchButton);

    QVBoxLayout *sLayout = new QVBoxLayout;
    sLayout->addLayout(sLayout_1);
    sLayout->addLayout(sLayout_2);
    QFrame *sFrame = new QFrame;
    sFrame->setFrameStyle(QFrame::StyledPanel);
    sFrame->setLayout(sLayout);

    supplierModel = new QSqlTableModel(supplierPage, mysql->myDB);//关联数据库
    supplierModel->setTable("supplier");//选择数据表
    supplierModel->setEditStrategy(QSqlTableModel::OnManualSubmit);//设置保存策略为手动提交
    supplierModel->setHeaderData(0,Qt::Horizontal, "序号");
    supplierModel->setHeaderData(1,Qt::Horizontal, "商家名称");
    supplierModel->setHeaderData(2,Qt::Horizontal, "所在地");
    supplierModel->setHeaderData(3,Qt::Horizontal, "添加日期");
    supplierModel->setHeaderData(4,Qt::Horizontal, "经营类目");
    supplierModel->setHeaderData(5,Qt::Horizontal, "商品数量");
    supplierModel->setHeaderData(6,Qt::Horizontal, "联系人");
    supplierModel->setHeaderData(7,Qt::Horizontal, "联系方式");
    supplierModel->select(); //选取整个表的所有行

    QTableView *tableView = new QTableView(this);
    tableView->setModel(supplierModel);
    tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);//使其不可编辑

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addLayout(titleLayout);
    layout->addWidget(sFrame);
    layout->addWidget(tableView);
    supplierPage->setLayout(layout);
    return supplierPage;
}

这个函数主要是实现了一个widget控件,这个控件就是按照咱们的原型设计来实现的,上部分是信息检索输入区,通过label、lineEdit、dateEdit、comboBox、pushButton等控件以及各种横向和纵向的layout来布局,并放到一个QFrame中框起来。

下半部分是一个QTableView,简单来说就是个表格,这个表格将我们的QSqlTableModel对象supplierModel置入,supplierMode将我们的数据库作为参数传入,并选择数据库中的supplier表格。

接下来我们将creatStackWidget()中第二个标签页中的label改为我们刚才新建的这个widget。

void MainWindow::creatStackWidget()
{
    stackWidget = new QStackedWidget;

    QLabel *label1 = new QLabel("1");
    QWidget *supplierPage = creatSupplierPage();
    QLabel *label3 = new QLabel("3");
    QLabel *label4 = new QLabel("4");
    QLabel *label5 = new QLabel("5");
    QLabel *label6 = new QLabel("6");
    stackWidget->addWidget(label1);
    stackWidget->addWidget(supplierPage);
    stackWidget->addWidget(label3);
    stackWidget->addWidget(label4);
    stackWidget->addWidget(label5);
    stackWidget->addWidget(label6);
    setCentralWidget(stackWidget);
}

运行之后,点击“供应商管理”,可以看到我们新建的供应商分页已经能显示出来啦。

3、增加数据

接下来我们实现添加供应商信息。

首先我们需要构建一个对话框来接收用户输入的供应商信息。

我们添加一个类,类名称我这里命名为“addSupplierDialog”,基本类我们选择custom。

建好类后,我们打开头文件,将内容修改如下,即该类是继承于QDialog,并声明了一些输入类控件,用来获取用户输入的信息:

#ifndef ADDSUPPLIERDIALOG_H
#define ADDSUPPLIERDIALOG_H

#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QDateEdit>
#include <QComboBox>
#include <QPushButton>

class addSupplierDialog : public QDialog
{
    Q_OBJECT

public:
    addSupplierDialog(QWidget *parent = nullptr);
    ~addSupplierDialog();

    QLineEdit *nameEdit;
    QComboBox *addrEdit;
    QComboBox *categoryEdit;
    QLineEdit *contactEdit;
    QLineEdit *teleEdit;
    QPushButton *addButton;
};

#endif // ADDSUPPLIERDIALOG_H

我们再打开cpp文件,将构造函数修改如下,完成对话框的界面。

#include "addsupplierdialog.h"
#include <QGridLayout>

addSupplierDialog::addSupplierDialog(QWidget *parent)
    : QDialog(parent)
{
    QLabel *nameLabel = new QLabel("商家名称");
    nameEdit = new QLineEdit;
    QLabel *addrLabel = new QLabel("商家所在地");
    addrEdit = new QComboBox;
    QStringList addrList;
    addrList<<"北京"<<"上海"<<"广州"<<"深圳"<<"重庆";
    addrEdit->addItems(addrList);
    QLabel *categoryLabel = new QLabel("经营类目");
    categoryEdit = new QComboBox;
    QStringList categoryList;
    categoryList<<"家电"<<"数码"<<"家居"<<"服饰"<<"食品";
    categoryEdit->addItems(categoryList);
    QLabel *contactLabel = new QLabel("联系人");
    contactEdit = new QLineEdit;
    QLabel *teleLabel = new QLabel("联系方式");
    teleEdit = new QLineEdit;
    addButton = new QPushButton("添加");

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(nameLabel,0,0);
    layout->addWidget(nameEdit,0,1);
    layout->addWidget(addrLabel,1,0);
    layout->addWidget(addrEdit,1,1);
    layout->addWidget(categoryLabel,2,0);
    layout->addWidget(categoryEdit,2,1);
    layout->addWidget(contactLabel,3,0);
    layout->addWidget(contactEdit,3,1);
    layout->addWidget(teleLabel,4,0);
    layout->addWidget(teleEdit,4,1);
    layout->addWidget(addButton,5,1);

    setLayout(layout);
    setWindowModality(Qt::WindowModal);
}

接下来,我们回到mainwindow.h中,将addsupplierdialog.h引入,并在mainwindow类中声明一个addSupplierDialog的实例对象:

addSupplierDialog *supplierDialog;

我们再声明一个槽函数,用来接收“添加”按钮触发后的信号,函数名就命名为addSupplier吧。

void addSupplier();

我们在mainwindow.cpp的creat中将“添加”按钮和槽函数addSupplier()关联在一起,并将addSupplier()函数体补充完整。

connect(addButton,&QPushButton::clicked,this,&MainWindow::addSupplier);

void MainWindow::addSupplier()
{
    supplierAddDialog = new addSupplierDialog(this);
    supplierAddDialog->show();
    connect(supplierAddDialog->addButton,&QPushButton::clicked,this,&MainWindow::insertSupplierData);
}

即点击“添加”按钮之后,添加对话框初始化并显示出来,同时,将对话框中的“添加”按钮与一个叫insertSupplierData的槽函数关联在一起。

那insertSupplierData要实现哪些内容呢,这里就需要我们通过QSqlTableModel的实例supplierModel与数据库进行交互啦。

在头文件中声明好insertSupplierData后,我们将这个槽函数的内容补充如下:

void MainWindow::insertSupplierData()
{
    QString supplierName = supplierDialog->nameEdit->text();
    QString supplierAddr = supplierDialog->addrEdit->currentText();
    QDate currentDate = QDateTime::currentDateTime().date();
    QString supplierDate = currentDate.toString("yyyy.MM.dd");
    QString suppliercategory = supplierDialog->categoryEdit->currentText();
    QString supplierContact = supplierDialog->contactEdit->text();
    QString supplierTele = supplierDialog->teleEdit->text();

    QSqlRecord record = supplierModel->record();
    record.setValue(1,supplierName);
    record.setValue(2,supplierAddr);
    record.setValue(3,supplierDate);
    record.setValue(4,suppliercategory);
    record.setValue(6,supplierContact);
    record.setValue(7,supplierTele);
    supplierModel->insertRecord(supplierModel->rowCount(), record);
    supplierModel->submitAll();
}

运行一下,我们在供应商信息添加按钮中输入一些测试数据,然后点击“添加”,可以看到,添加的信息已经保存在数据库中,并在tableView中显示出来了。

这里商品数量我们还没有具体数据,后续我们会和其他表做关联获取具体的数据后,将这块儿补充完整。

4、查询数据

我们希望用户可以通过“商户名称”、“商户名称”、“商户所在地”、“添加日期”、“经营品类”作为查询项来查询数据库信息。

我们在mainwindow中新建一个槽函数:void searchSupplierData();

槽函数内容如下:

void MainWindow::searchSupplierData()
{
    QString id =  QString("id = '%1'").arg(supplierIdEdit->text());
    QString name =  QString("name = '%1'").arg(supplierNameEdit->text());
    QString address = QString("addr = '%1'").arg(supplierAddrEdit->currentText());
    QString date = QString("date = '%1'").arg(supplierDateEdit->date().toString("yyyy.MM.dd"));
    QString category = QString("category = '%1'").arg(supplierCateEdit->currentText());
    QString filterStr = "";
    if(!supplierIdEdit->text().isEmpty())
        filterStr.append(id);
    if(!supplierNameEdit->text().isEmpty())
    {
        if(!filterStr.isEmpty())
            filterStr.append(" and ");
        filterStr.append(name);
    }
    if(!supplierAddrEdit->currentText().isEmpty())
    {
        if(!filterStr.isEmpty())
            filterStr.append(" and ");
        filterStr.append(address);
    }
    if(!filterStr.isEmpty())
        filterStr.append(" and ");
    filterStr.append(date);
    if(!supplierCateEdit->currentText().isEmpty())
    {
        if(!filterStr.isEmpty())
            filterStr.append(" and ");
        filterStr.append(category);
    }
    supplierModel->setFilter(filterStr);
    supplierModel->select();
}

这里我们构建了一个过滤器filter,然后用QSqlTableModel的setFilter查询出符合条件的数据。

我们可以运行测试一下,发现可以正常查询出符合条件的数据。

5、修改数据

接下来我们来实现修改信息的功能。

我们在mainwindow中增加一个槽函数void modifySupplier();,用来处理修改按钮触发后的操作。

槽函数的内容如下:

void MainWindow::modifySupplier()
{
    supplierModifyDialog = new modifySupplierDialog(this);
    int curRow = supplierTableView->currentIndex().row();
    QSqlRecord record = supplierModel->record(curRow);

    QString name = record.value(1).toString();
    supplierModifyDialog->nameEdit->setText(name);
    QString address = record.value(2).toString();
    supplierModifyDialog->addrEdit->setCurrentText(address);
    QString category = record.value(4).toString();
    supplierModifyDialog->categoryEdit->setCurrentText(category);
    QString contact = record.value(6).toString();
    supplierModifyDialog->contactEdit->setText(contact);
    QString telephone = record.value(7).toString();
    supplierModifyDialog->teleEdit->setText(telephone);

    connect(supplierModifyDialog->modifyButton,&QPushButton::clicked,this,&MainWindow::modifySupplierData);
    supplierModifyDialog->show();
}

可以看到,和添加数据一样,我们点击“修改”按钮后,需要弹出来一个对话框,对话框将用户选择的数据显示出来并支持用户修改。

下面我们看看这个“修改对话框”是如何实现的:

我们新建一个类,命名为modifySupplierDialog,基础类为自定义。

新建成功后,我们打开其头文件,修改如下:

#ifndef MODIFYSUPPLIERDIALOG_H
#define MODIFYSUPPLIERDIALOG_H

#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QDateEdit>
#include <QComboBox>
#include <QPushButton>

class modifySupplierDialog : public QDialog
{
    Q_OBJECT

public:
    modifySupplierDialog(QWidget *parent = nullptr);
    ~modifySupplierDialog();

    QLineEdit *nameEdit;
    QComboBox *addrEdit;
    QComboBox *categoryEdit;
    QLineEdit *contactEdit;
    QLineEdit *teleEdit;
    QPushButton *modifyButton;
};

#endif // MODIFYSUPPLIERDIALOG_H

然后我们打开它的cpp文件,将其构造函数补充完整。

difysupplierdialog.h"
#include <QGridLayout>

modifySupplierDialog::modifySupplierDialog(QWidget *parent)
    : QDialog(parent)
{
    QLabel *nameLabel = new QLabel("商家名称");
    nameEdit = new QLineEdit;
    QLabel *addrLabel = new QLabel("商家所在地");
    addrEdit = new QComboBox;
    QStringList addrList;
    addrList<<"北京"<<"上海"<<"广州"<<"深圳"<<"重庆";
    addrEdit->addItems(addrList);
    QLabel *categoryLabel = new QLabel("经营类目");
    categoryEdit = new QComboBox;
    QStringList categoryList;
    categoryList<<"家电"<<"数码"<<"家居"<<"服饰"<<"食品";
    categoryEdit->addItems(categoryList);
    QLabel *contactLabel = new QLabel("联系人");
    contactEdit = new QLineEdit;
    QLabel *teleLabel = new QLabel("联系方式");
    teleEdit = new QLineEdit;
    modifyButton = new QPushButton("修改");

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(nameLabel,0,0);
    layout->addWidget(nameEdit,0,1);
    layout->addWidget(addrLabel,1,0);
    layout->addWidget(addrEdit,1,1);
    layout->addWidget(categoryLabel,2,0);
    layout->addWidget(categoryEdit,2,1);
    layout->addWidget(contactLabel,3,0);
    layout->addWidget(contactEdit,3,1);
    layout->addWidget(teleLabel,4,0);
    layout->addWidget(teleEdit,4,1);
    layout->addWidget(modifyButton,5,1);

    setLayout(layout);
    setWindowModality(Qt::WindowModal);
}
modifySupplierDialog::~modifySupplierDialog()
{

}

在mainwindow.cpp中将修改按钮的信号和槽函数连接起来:

QPushButton *searchButton = new QPushButton("搜索");
    connect(searchButton,&QPushButton::clicked,this,&MainWindow::searchSupplierData);

运行之后,选中表中有数据的某一行,点击“修改”按钮,可以看到弹出了修改对话框,对话框中的输入控件回显需要修改的数据。

用户修改信息后点击修改对话框中的“修改”按钮,则调用了我们定义的另一个槽函数void modifySupplierData(),将数据重新写入数据库中。

void MainWindow::modifySupplierData()
{
    QString supplierName = supplierModifyDialog->nameEdit->text();
    QString supplierAddr = supplierModifyDialog->addrEdit->currentText();
    QString suppliercategory = supplierModifyDialog->categoryEdit->currentText();
    QString supplierContact = supplierModifyDialog->contactEdit->text();
    QString supplierTele = supplierModifyDialog->teleEdit->text();

    int curRow = supplierTableView->currentIndex().row();
    QSqlRecord record = supplierModel->record(curRow);
    record.setValue(1,supplierName);
    record.setValue(2,supplierAddr);
    record.setValue(4,suppliercategory);
    record.setValue(6,supplierContact);
    record.setValue(7,supplierTele);

    if(supplierModel->setRecord(curRow, record))
    {
        supplierModifyDialog->close();
        supplierModel->submitAll();
        supplierTableView->setEnabled(true);
    }
}

运行之后,修改某行数据,可以看到修改成功。

6、删除数据

接下来我们实现删除数据库的某条数据。

在mainwindow中声明一个槽函数void deleteSupplierData();

函数体如下:

void MainWindow::deleteSupplierData()
{
    int curRow = supplierTableView->currentIndex().row();
    supplierModel->removeRow(curRow);
    int ok = QMessageBox::warning(this,tr("删除当前行!"),
                                      tr("你确定删除当前行吗?"),
                                      QMessageBox::Yes,QMessageBox::No);
        if(ok == QMessageBox::No)
            supplierModel->revertAll(); //如果不删除,则撤销
        else
            supplierModel->submitAll(); //否则提交,在数据库中删除该行
}

先获取用户所选择的行数,然后调用removeRow,这里设置了一个二次确认的弹窗,用户点击“yes”,删除成功,用户点击“no”,则取消删除。

连接按钮信号和槽函数,运行一下,可以看到,点击“删除”按钮可以成功删除选中的数据行。

7、总结

这一章节,我们通过使用QSqlTableModel这个类的实例,来与数据库交互,实现了数据的增、删、改、查,后续其他的页面,包括“商品管理”、“库存管理”等页面,也都可以按照这个思路和方法来实现。

发布了8 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/hello_monster/article/details/98729909