汽车销售管理系统
一、功能分析和界面设计
1. 功能分析
窗口流程
- 首先,要求出现输入密码的窗口。
- 其次,进入销售管理主界面后,第一个页面是品牌车管理,第二个页面是销售统计。通过菜单栏来进行切换。
- 最后,退出。
管理流程
2. 主界面设计
新建 Qt Widgets Application, 项目名称“manager”,基类为“QWidget”。
2.1 主界面
进行 UI 设计,主界面宽高设置:
然后“windowTitle”设置为“汽车销售管理系统”。
2.2 Stacked Widget
QStackedWidget 允许在其中堆叠多个页面或面板,并且每个页面内部都可以有自己的布局和内容。但同一时间,只有一个页面是可见的,这使得它非常适合用于实现标签页、向导或其他需要在多个视图之间切换的场景。
本例子中,需要拖入 Stacked Widget。来实现管理页面和统计页面的视图切换。将其宽高修改为700*410。然后我们计划是设计2个Page,第一个 Page,将currentPageName 修改为 managePage。第二个 Page,修改为 chartPage。
然后再当前页面(managePage)拖入 Label、Tool Box 和 List Widget部件。
ToolBox
是Qt框架中的一个窗口容器类,用于实现多个页面的切换和显示。我们将其放在左侧。本例子不为 ToolBox 添加额外的页面来扩充功能。
List Widget
Qt框架提供的一个用于显示列表的控件。用于在窗口中显示一个可滚动的列表。每个列表项都可以是一个文本项、图像项或自定义项。
最后,我们添加 Combo Box、Line Edit、Spin Box 和 Push Button。
然后,我们更改各个部件的 objectName 属性,一定要有可读性。
3. 菜单设计
在“widget.h”添加头文件:
#include <QMainWindow>
#include <QMenuBar>
两个头文件,它们分别用于创建主窗口和菜单栏。
-
在QMainWindow中添加QMenuBar
- 创建一个QMainWindow对象。
- 创建一个QMenuBar对象(但通常不需要显式创建,因为QMainWindow已经有一个内置的菜单栏)。
- 使用QMainWindow的menuBar()方法获取到内置的QMenuBar。
- 创建QMenu对象,并将它们添加到QMenuBar中。
- 创建QAction对象,并将它们添加到QMenu中。
- 可选:连接QAction的触发信号到自定义的槽函数。
public:
QMenu *manageMenu;
QMenu *passwordMenu;
QAction *manageAction;
QAction *chartAction;
QAction *quitAction;
修改 Widget 的基类为 QMainWindow(类定义和构造函数都要改),并添加主菜单、动作的定义:
二、实现功能
1. 出售车辆
1.1 创建表
首先创建两张表:一张厂家表和一张品牌表。
厂家表中存放三家汽车生成商;品牌表保存所有品牌汽车所述厂家、总量、销售量和库存量等数据。
需要注意的是,本程序要用到 QtSql 和 QtXml,故要在 .pro 文件添加:QT += sql xml
。
然后再创建新的头文件,conection.h
。添加 static bool createConnection() 函数
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName("easybook-3313b0"); //设置数据库主机名
db.setDatabaseName("data.db"); //创建一个 SQLite 数据库
db.setUserName("zhouhejun"); //设置数据库用户名
db.setPassword("123456"); //设置数据库密码
if(!db.open()){
//打开连接
//提示出错
return false;
}
QSqlQuery query; //Query 提供了一个执行SQL语句的接口并且可以遍历执行的返回结果集
//创建厂家表
query.exec("create table factory(id varchar primary key,name varchar)");
query.exec(QString("insert into factory values('0','请选择厂家')"));
query.exec(QString("insert into factory values('01','一汽大众')"));
query.exec(QString("insert into factory values('02','二汽神龙')"));
query.exec(QString("insert into factory values('03','上海大众')"));
//创建品牌表
query.exec("create table brand(id varchar primary key,name varchar,factory varchar,price int,sum int,sell int,last int)");
query.exec(QString("insert into brand values('01','奥迪A6','一汽大众',36,50,10,40)"));
query.exec(QString("insert into brand values('02','捷达','一汽大众',34,20,5,15)"));
query.exec(QString("insert into brand values('03','宝来','一汽大众',41,80,20,60)"));
query.exec(QString("insert into brand values('04','奔驰','一汽大众',83,40,15,25)"));
query.exec(QString("insert into brand values('05','毕加索','二汽神龙',39,50,15,35)"));
query.exec(QString("insert into brand values('06','富康','二汽神龙',28,60,10,50)"));
query.exec(QString("insert into brand values('07','标致307','二汽神龙',27,70,20,50)"));
query.exec(QString("insert into brand values('08','桑塔纳','上海大众',25,75,25,50)"));
query.exec(QString("insert into brand values('09','帕萨特','上海大众',27,65,20,45)"));
//创建密码表
query.exec("create table password(pwd varchar primary key)");
query.exec("insert into password values('123456')");
return true;
还要在 main.cpp 添加:
if(!createConnection()||!createXml())return 0;
createXml(),在后面的销售清单要用到。
1.2 加载厂家名称
setFixedSize(750,500); //固定窗口大小
createMenuBar();
ui->stackedWidget->setCurrentIndex(0); //第一页
QSqlQueryModel *factoryModel = new QSqlQueryModel(this); //在Qt应用程序中执行SQL查询并以模型的形式提供数据
factoryModel->setQuery("select name from factory"); //选择 name 字段的,具体看上面的厂家表
ui->sellFactoryComboBox->setModel(factoryModel); //将factoryModel 设置为 下拉框
1.3 加载厂家对应的品牌名
首先是要选择“厂家”组合框中的任意一家,才能对应“品牌”的组合框显示厂家相应的品牌的品牌汽车。于是要触发 sellFactoryComboBox 的 currentIndexChanged(QString) 的改变选项事件信号,实现槽函数中 加载对应品牌名的功能。
而具体的逻辑,看代码理解。
void Widget::on_sellFactoryComboBox_currentIndexChanged(const QString &arg1)
{
if(arg1 == "请选择厂家"){
//取消选择或重置某些状态,进行其他部件的状态设置
on_sellCancelBtn_clicked();
}else{
//将sellBrandComboBox(品牌下拉框)设置为启用状态,允许用户选择。
ui->sellBrandComboBox->setEnabled(true);
//创建一个新的QSqlQueryModel对象,用于存储从数据库查询到的数据。
QSqlQueryModel *model = new QSqlQueryModel(this);
//使用setQuery方法设置查询语句,该语句根据sellFactoryComboBox的当前选中项(厂家)查询对应的品牌名称。
model->setQuery(QString("select name from brand where factory='%1'").arg(arg1));
//将这个模型设置为sellBrandComboBox的模型,这样下拉框中就会显示查询到的品牌名称。
ui->sellBrandComboBox->setModel(model);
//将sellCancelBtn(取消按钮)设置为启用状态,允许用户点击。
ui->sellCancelBtn->setEnabled(true);
}
}
1.4 加载某品牌的报价和数量
选择品牌后,要求下方的“报价”和“数量”显示相应的信息。同样的方式,触发 sellBrandComboBox 部件的 currentIndexChanged(QString) 改变选项事件的信号,实现槽函数中 加载报价和数量的功能。
void Widget::on_sellBrandComboBox_currentIndexChanged(const QString &arg1)
{
//重置旋转框的数量和加法框的金额,确定键也不让按
ui->sellNumSpinBox->setValue(0);
ui->sellNumSpinBox->setEnabled(false);
ui->sellSumLineEdit->clear();
ui->sellSumLineEdit->setEnabled(false);
ui->sellOkBtn->setEnabled(false);
QSqlQuery query;
//使用SQL查询语句根据品牌名称和厂家查询价格
query.exec(QString("select price from brand where name='%1' and factory='%2'").arg(arg1).arg(ui->sellFactoryComboBox->currentText()));
query.next();
//将价格行编辑器(sellPriceLineEdit)设置为启用和只读,并显示查询到的价格。
ui->sellPriceLineEdit->setEnabled(true);
ui->sellPriceLineEdit->setReadOnly(true);
ui->sellPriceLineEdit->setText(query.value(0).toString());
//使用另一个SQL查询语句根据品牌名称和厂家查询剩余数量
query.exec(QString("select last from brand where name='%1' and factory='%2'").arg(arg1).arg(ui->sellFactoryComboBox->currentText()));
//将查询的结果集的游标移动到下一行
query.next();
//上一句获得数据后,获取当前行中指定列的值。
int num = query.value(0).toInt();
// 如果剩余数量为0,则显示一个消息框提示用户该品牌汽车已经售完
if(num == 0){
QMessageBox::information(this,tr("提示"),tr("该品牌汽车已经售完!"),QMessageBox::Ok);
}
else{
//如果剩余数量大于0,则启用销售数量旋转框,并设置其最大值为剩余数量。同时显示剩余数量的标签。
ui->sellNumSpinBox->setEnabled(true);
ui->sellNumSpinBox->setMaximum(num);
ui->sellLastNumLabel->setText(tr("剩余数量:%1").arg(num));
ui->sellLastNumLabel->setVisible(true);
}
}
1.5 显示购车总价
更改旋转框的数量后,要求显示总金额。即 触发 sellNumSpinBox 部件的 valueChanged(int) 信号后,实现槽函数中的 显示总金额功能。
void Widget::on_sellNumSpinBox_valueChanged(int arg1)
{
// 数量为0,清除金额,禁用sellSumLineEdit,不能编辑文本框,不让点确定
if(arg1 == 0){
ui->sellSumLineEdit->clear()