商品库存管理系统 运行效果
商品库存管理系统 功能模块
新增商品功能模块
库存功能
删除、添加商品种类、查询、修改数量、导出成为excel
主窗口UI设计
- 设置主窗口的背景颜色
- 以及各个控件的添加和控件的风格

遇到的问题:
设置窗口背景的方法
QPalette palette=this->palette();
palette.setColor(QPalette::Background,"#BDE582");//窗口颜色
this->setPalette(palette);
表格控件初始化
-
表头、列数、行数
-
设置列宽
void MainWidget::tableWidgetInt()
{
QStringList head;
ui->tableWidget->setRowCount(10);
ui->tableWidget->setColumnCount(8);
head<<"编号"<<"名称"<<"数量"<<"单价"<<"供应商家"<<"负责人"<<"入库时间"<<"出库时间";
ui->tableWidget->setHorizontalHeaderLabels(head);//设置表头
ui->tableWidget->setColumnWidth(0,40);//设置列宽
ui->tableWidget->setColumnWidth(2,60);
ui->tableWidget->setColumnWidth(3,60);
ui->tableWidget->setColumnWidth(4,140);
ui->tableWidget->setColumnWidth(5,100);
ui->tableWidget->setColumnWidth(6,160);
ui->tableWidget->setColumnWidth(7,160);}
连接数据库
- 使用QODBC的方式
- 连接数据库的IP、端口、数据库名、密码
void MainWidget::sqlConnect()
{
QSqlDatabase db=QSqlDatabase::addDatabase("QODBC");
db.setHostName("127.0.0.1");
db.setPort(3306);
db.setDatabaseName("stockmsdb");
db.setPassword("5320240388");
bool bok=db.open();
if(!bok)
{
QMessageBox::information(this,"提示","连接不成功");
}
}
初始化mysql数据到Qt表格中
-
查询数据的方法:根据mysql的指定字段和对应字段的数据,使用where 查询。用字符串的方式组合生成sql语句。然后传给mysql
-
mysql的结果回传给qt的方法:sqlquery循环读取每个字段对应的数据,得到的数据转换成字符串,然后传给tablewidget的item中
-
查询只会需要更新表,重新生成
void MainWidget::tableDataInt()
{
QString str=("select *from goods;");//sql查询语句格式
QSqlQuery sql;
if(!sql.exec(str))//进行查询
{
QMessageBox::information(this,"提示","查询不成功");
return ;
}
int j=0;
while(sql.next())//获取查询到的结果
{
for(int i=0;i<=7;i++)
{
ui->tableWidget->setItem(j,i,new QTableWidgetItem(sql.value(i).toString()));
}
j++;
}}
新增商品新种类导数据到mysql中
- 设置新增商品的对话框的UI
- 将对话框得到的数据导入字符串中
- 将字符串转sql语句转给mysql数据库
- 其中需要解决点:获取当前入库时间,以及对话框为空的问题
UI设计:

插入数据设计:
void add_product::on_pushButton_add_clicked()
{
//获取插入数据
QString id=ui->lineEdit_id->text();
if(id.isEmpty())
{
QMessageBox::critical(this,"警告","编号不能为空!");
ui->lineEdit_id->setFocus();
return;
}
QString name="'"+ui->lineEdit_name->text()+"'";
QString amount="'"+ui->lineEdit_amount->text()+"'";
QString price="'"+ui->lineEdit_price->text()+"'";
QString saller="'"+ui->lineEdit_saller->text()+"'";
QString director="'"+ui->lineEdit_director->text()+"'";
QString intodatetime="'"+QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")+"'";//获取mysql对应格式时间
QString targetdata=id+","+name+","+amount+","+price+","+saller+","+director+","+intodatetime+","+"NULL";
//组合生成sql代码
QString insertsent=QString("insert into goods (id,product_name,product_amount,product_price,product_saller,product_director,product_into_time,product_out_time)values(%1)").arg(targetdata);
//进行执行sql
QSqlQuery sql;
if(!sql.exec(insertsent))
{
QMessageBox::critical(this,"警告","新增商品失败");
}
else
{
QMessageBox::information(this,"通知","新增商品成功");
}
}
商品查询
QString name=ui->lineEdit_name->text();//根据商品名查询
if(name.isEmpty())
{
QMessageBox::critical(this,"警告","商品名称不能为空");
ui->lineEdit_name->setFocus();
return;
}
ui->tableWidget->clear();//清除之前的表只为得到对应数据
QString selectsql=QString("select *from goods where product_name=%1;").arg("'"+name+"'");
QSqlQuery sql;
if(!sql.exec(selectsql))
{
QMessageBox::information(this,"提示","查询不成功");
return ;
}
int j=0;
while(sql.next())
{
for(int i=0;i<=7;i++)
{
ui->tableWidget->setItem(j,i,new QTableWidgetItem(sql.value(i).toString()));
}
j++;
}
商品入库
- 修改商品的数量
- 用字符串的方式获取商品数量
- 将字符串作为sql语句传给mysql
UI设计:获取当前所有id值
void add_amount::interfaceInit()
{
QSqlQuery sql;
QString getid=QString("select id from goods");
if(!sql.exec(getid))
{
QMessageBox::information(this,"提示","获取不成功");
return ;
}
while(sql.next())
{
ui->comboBox_id->addItem(sql.value(0).toString());
}
}
更改数量
获取当前已有的数量
QString selectId=ui->comboBox_id->currentText();
QString selectAmount=QString("select product_amount from goods where id=%1;").arg("'"+selectId+"'");//获取当前id对应的数量
QSqlQuery sql;
if(!sql.exec(selectAmount))
{
QMessageBox::critical(this,"警告","查询失败1");
return ;
}
int currentquantity;
while(sql.next())
{
currentquantity=sql.value(0).toInt();
}
将已有数量与新加的数量相加,然后发送信号让主页面自动更改窗口
QString updateAmount=QString("update goods set product_amount=%1 where id=%2;").arg(QString::number(sumQuantity)).arg(selectId);
if(!sql.exec(updateAmount))
{
QMessageBox::critical(this,"警告","查询失败2");
return ;
}
else
{emit dataConfirmed(); // ✅ 发射信号给主窗口,让主窗口自动更新页面
QMessageBox::information(this,"通知","插入成功");
}
商品出库
-
获取数据库中对应商品数据
-
通过下拉框的改变,进行更改商品数据,首先获取id值,找到对应id值的数据,添加数量。
-
将数据修改之后转换为sql语句发给mysql中
void delete_amount::on_pushButton_out_clicked()//减少数量 { QString selectId=ui->comboBox_id->currentText(); QString selectAmount=QString("select product_amount from goods where id=%1;").arg("'"+selectId+"'"); QSqlQuery sql; if(!sql.exec(selectAmount)) { QMessageBox::critical(this,"警告","查询失败1"); return ; } int currentquantity; while(sql.next()) { currentquantity=sql.value(0).toInt(); } int sumQuantity=(currentquantity-ui->lineEdit_amount->text().toInt())>=0?currentquantity-ui->lineEdit_amount->text().toInt():0;//防止数量为负数 QString updateAmount=QString("update goods set product_amount=%1 where id=%2;").arg(QString::number(sumQuantity)).arg(selectId); if(!sql.exec(updateAmount)) { QMessageBox::critical(this,"警告","出库失败2"); return ; } else { emit dataConfirmed(); QMessageBox::information(this,"通知","出库成功"); } } void delete_amount::interfaceInit()//ui设计 { QSqlQuery sql; QString getid=QString("select id from goods"); if(!sql.exec(getid)) { QMessageBox::information(this,"提示","获取不成功"); return ; } while(sql.next()) { ui->comboBox_id->addItem(sql.value(0).toString()); } }
下架商品
-
找到当前选中行
-
获取选中行的id
-
根据id对mysql的一行数据进行删除
-
刷新当前表格
//清空商品
//获取当前的item
if(ui->tableWidget->currentRow()>=0)//判断当前是否选中行
{
int btn= QMessageBox::information(this,"删除数据","你确定删除当前选中数据?",QMessageBox::Ok,QMessageBox::No);
if(btn==QMessageBox::Ok)
{
//获取当前item的所在行
int iRow=ui->tableWidget->currentRow();
QString delid=ui->tableWidget->model()->index(iRow,0).data().toString();//获取这一行的id
QString selectAmount=QString("select *from goods where id=%1;").arg("'"+delid+"'");
QSqlQuery sql;
if(!sql.exec(selectAmount))
{
QMessageBox::critical(this,"警告","查询id失败");
return ;
}
QString delstr=QString("delete from goods where id='%1';").arg(delid);
if(!sql.exec(delstr))
{
QMessageBox::critical(this,"警告","删除失败");
return ;
}
else
{
ui->tableWidget->clear();
tableWidgetInt();
QMessageBox::information(this,"通知","删除商品成功");} }} else { QMessageBox::information(this,"删除数据","你没有选中要删除的行",QMessageBox::Ok,QMessageBox::No); return ; }
表格数据转Excel
-
生成文件名:使用当前时间作为文件名前缀
-
选择保存路径
-
创建Excel对象:通过COM接口操作Excel
-
写入表头和数据
//将时间作为文件名前缀 QString timestr = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm"); //创建文件并获取文件名 QString strFileName = QFileDialog::getSaveFileName(this, "保存文件", QString("./%1%2.xlsx").arg(timestr).arg("_kcgl"), "Excel Files(*.xlsx)"); // ✅ 修复5: 改为.xlsx if(!strFileName.isEmpty()) { // 测试文件创建权限后,立即删除测试文件,避免占用 QFile testFile(strFileName); if(testFile.open(QIODevice::WriteOnly)) { testFile.close(); testFile.remove(); // ✅ 修复6: 立即删除,释放文件占用 qDebug() << "文件路径权限检查通过。"; QAxObject *excel = new QAxObject(); if(excel->setControl("Excel.Application")) { excel->dynamicCall("SetVisible(bool)", false); excel->setProperty("DisplayAlerts", false); // 获取工作簿集合 QAxObject *workbooks = excel->querySubObject("WorkBooks"); if(!workbooks) { /* 错误处理 */ } workbooks->dynamicCall("Add"); // 获取活动工作簿 QAxObject *workbook = excel->querySubObject("ActiveWorkBook"); if(!workbook) { /* 错误处理 */ } // 获取第一个工作表 QAxObject *worksheets = workbook->querySubObject("Worksheets"); QAxObject *worksheet = worksheets->querySubObject("Item(int)", 1); // 也可用 Worksheets(int) if(!worksheet) { /* 错误处理 */ } // ✅ 修复2: 添加表头安全检查 int columnCount = ui->tableWidget->columnCount(); for(int i = 0; i < columnCount; i++) { QAxObject *cell = worksheet->querySubObject("Cells(int,int)", 1, i+1); if(cell) { QTableWidgetItem *header = ui->tableWidget->horizontalHeaderItem(i); if(header) { cell->dynamicCall("SetValue(const QString&)", header->text()); } delete cell; // ✅ 修复1: 循环内立即释放 } } // ✅ 修复2 & 4: 添加数据安全检查,并移除多余的"\t" int rowCount = ui->tableWidget->rowCount(); for(int i = 0; i < rowCount; i++) { for(int j = 0; j < columnCount; j++) { QAxObject *cell = worksheet->querySubObject("Cells(int,int)", i+2, j+1); if(cell) { QTableWidgetItem *item = ui->tableWidget->item(i, j); QString text = item ? item->text() : ""; // ✅ 修复4: 不再添加 "\t" // 可选:处理以0开头的数字等格式 if(text.toInt() == text.toDouble() && text.length()>1 && text.startsWith('0')) { text = "'" + text; } cell->dynamicCall("SetValue(const QString&)", text); delete cell; // ✅ 修复1: 循环内立即释放 } } } // 保存文件 workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(strFileName)); workbook->dynamicCall("Close()"); excel->dynamicCall("Quit()"); // ✅ 修复3: 按创建顺序的反序,安全释放所有COM对象 delete worksheet; delete worksheets; delete workbook; delete workbooks; delete excel; QMessageBox::information(this, "成功", "导出完成!"); } else { QMessageBox::critical(this, "错误", "无法启动Excel。"); delete excel; } } else { QMessageBox::critical(this, "错误", QString("无法创建文件:\n%1\n错误:%2").arg(strFileName).arg(testFile.errorString())); } }
商品汇总
-
读取数据库的内容
-
然后将单价与数量用sql语句进行合成,生成总价
-
用按键进行汇总
-
以及进行保存
void datasum::tableWidgetInt()
{
QStringList ls;
ls<<"编号"<<"名称"<<"数量"<<"单价"<<"总价"<<"供应商家"<<"负责人"<<"入库时间"<<"出库时间";
ui->tableWidget->setRowCount(100);
ui->tableWidget->setColumnCount(9);
ui->tableWidget->setHorizontalHeaderLabels(ls);
ui->tableWidget->setColumnWidth(0,40);
ui->tableWidget->setColumnWidth(2,60);
ui->tableWidget->setColumnWidth(3,60);
ui->tableWidget->setColumnWidth(4,40);
ui->tableWidget->setColumnWidth(5,140);
ui->tableWidget->setColumnWidth(6,120);
ui->tableWidget->setColumnWidth(7,160);
ui->tableWidget->setColumnWidth(8,160);}
void datasum::tableDataInt()
{
QSqlQuery sql;
QString selectsql="select *from goods;";
if(sql.exec(selectsql))
{
int i=0;
while(sql.next())
{
for(int j=0;j<ui->tableWidget->columnCount();j++)
{
if(j>=4)
{
ui->tableWidget->setItem(i,j+1,new QTableWidgetItem(sql.value(j).toString()));
}
else{
ui->tableWidget->setItem(i,j,new QTableWidgetItem(sql.value(j).toString()));
}} double amount=ui->tableWidget->item(i,2)->text().toInt(); double price=ui->tableWidget->item(i,3)->text().toInt(); ui->tableWidget->setItem(i,4,new QTableWidgetItem(QString::number(amount*price))); i++; } }}
void datasum::on_pushButton_data_sum_clicked()
{
tableWidgetInt();
tableDataInt();}