上一章节我们已经通过用户注册和登录功能初步接触了数据库,主要是通过QSqlQuery来与数据库进行交互,这种方式呢有一定局限性,需要比较懂sql语句,而且调用起来比较麻烦。下面我们通过使用QSqlTableModel来和数据库交互,QSqlTableModel是一个Qt封装好的数据库模型类,关联好数据库和数据表之后,我们只需要和它打交道就可以操控数据库啦。
目录
1、创建数据表
2、构建UI
3、增加数据
4、查询数据
5、修改数据
6、删除数据
7、总结
1、创建数据表
现在数据库中只有一个简单的用户表,用来记录用户数据,我们接下来向数据库中添加其他数据表,用来记录供应商信息、商品信息等。
创建表格之前还是先设计表结构,下面是我设计的商家表和商品表的表结构,当然,你可以按照自己的实际情况去设计,这里只是一个示例。表结构一般也会随着开发过程不断调整,但最好是在开始能设计的合理一些,减少一些不必要的调整。
供应商信息表的表结构设计如下:
商品信息表的表结构设计如下:
我们在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这个类的实例,来与数据库交互,实现了数据的增、删、改、查,后续其他的页面,包括“商品管理”、“库存管理”等页面,也都可以按照这个思路和方法来实现。