0%

C# Winform简单模拟水果店结账系统

简介

现实生活中,结账系统无处不在,屡见不鲜,各种结账系统 例如:订餐结账系统,超市购物结账系统,酒店客房结账系统等等.

其实结账原理都大同小异,即将所有购买项的价格都相加,当然,那些复杂的系统所考虑的方面和功能就很多了,我们这里不考虑.

那么,今天我们这里简单的写个基于 C# winform 平台的水果店结账系统.

原理

这里用到了一个主窗体类和一个构造函数类(用于存取物品的属性) 以及一个写有物品属性的文本文件(目的是方便后期更改物品的价格,折扣等属性).

首先,通过FileStream的OpenRead方法来打开并读取文本文件, 然后调用StreamReader类来读取FileStream的字符并将里面的字节转换成字符串.

具体FileStream和StreamReader的用法,可以参考这里. 从文本里获取到物品的属性之后,将其存到一个具有物品属性的数据结构的泛型list里.

然后在各个物品按钮下调用不同物品,每个物品在泛型list里的索引也是不一样的.之后再用一个整型数组来存储每个物品按钮的点击次数,即为每个物品的购买次数.

还用到一个泛型list来装载每个物品的价格,在计算总价的时候遍历并相加, 得到一个总价.

这里还用到了一个优惠价,即每个物品都有不同的打折方式(代码里有详细注释), 用到了一些简单的算法,并且在结账的时候自动计算每项物品最终优惠了多少.

然后用 总价-优惠价=最终我们应该支付的价格,当然这里也实现了物品清空的功能.

界面设计

img

fruits.txt文本内容

img

代码如下

ProductAttribute.cs 类里的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class ProductAttribute
{
//初始化各值
string name = "";
float price = 0;
int code1 = 0;
int code2 = 0;
//构造方法
public ProductAttribute(string n, float p, int c1, int c2)
{
//实现ProductAttribute的数据结构
//里面可以传入如下参数
name = n;
price = p;
code1 = c1;
code2 = c2;
}
//可以读取ProductAttribute里的Name 属性
public string Name
{
get { return name; }
}
//可以读取ProductAttribute里的Price 属性
public float Price
{
get { return price; }
}
// 一个save方法 用于判断 不同的折扣方式 并返回一个减去的钱数
public float save(int n)
{
float m = 0; //m用于获取 打折后的 价格 符合的物品数量
switch (code1)
{
case 0: //code1为0 的时候
m = n; //买多少斤 最终价格还是 按多少斤算
break;
case 1: //code1为1的时候 有2种情况
if (code2 == 0) //code2为0 买1斤 第2斤免费 即买一送一
m = (float)((n / 2) + (n % 2)); //买1斤 第2斤免费 但买3斤 还是1斤免费
else if (code2 == 1) //code2为1 这里是买1斤 第2斤半价 即买2斤 1斤半的钱 买4斤 3斤的钱
m = (float)(1.5 * (n / 2) + (n % 2));
break;
case 2: //code1 为2的时候 也有2种方法
if (code2 == 0) //code1为2 code2 为0 买2斤 第3斤免费
m = (float)(n - (n / 3));
else if (code2 == 1) //code1为2 code2为1 即买2斤 第3斤半价
m = (float)(n - 0.5 * (n / 3));
break;
}

float save = (n - m) * price; //计算出一个最终的价格
return save; //返回省去的钱数
}
}

主窗体类代码 frmFruitShopping.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
public partial class frmFruitShopping : Form
{
public frmFruitShopping()
{
InitializeComponent();

this.Load += (s, e) => { ReadFruitsData(); FruitClick(); };
btnTotal.Click += (s, e) => { GetTotalCost(); };
btnEmpty.Click += (s, e) => { EmptyShoppingBox(); };
btnDeleteOne.Click += (s, e) => { DeleteOneShoppingItem(); };
}

List<ProductAttribute> productList;

/// <summary>
/// 读取txt文本数据
/// </summary>
private void ReadFruitsData()
{
//创建一个水果属性的集合
productList = new List<ProductAttribute>();
string strRead; //创建一个字符串 用来接受读取的数据
// 创建FileStream文件流 可以用来读取任何文件 其内部读取格式是 最原始的字节
FileStream fs = File.OpenRead("fruits.txt");
//通过流读取来读取fs文件里的东西,并将 文字格式设置为默认的ANSI编码
using (StreamReader sr = new StreamReader(fs, Encoding.Default))
{
//用while循环来 一行行读取 如果读到的内容不为空 则进入循环 否则不读
while ((strRead = sr.ReadLine()) != null)
{
//这里用到了个字符串分割 每行都有几个参数 通过'-' 隔开 分割后存到一个数组里
string[] part = strRead.Split('-');
//new一个 构造方法来装载 这些参数
ProductAttribute pa = new ProductAttribute(part[0], (float)Convert.ToDouble(part[1]), Convert.ToInt32(part[2]), Convert.ToInt32(part[3]));
//将 装载的参数 存到水果属性的list集合中
productList.Add(pa);
}
}
}

//创建一个TotalCost集合 来装载 所有的开销
List<float> TotalCost = new List<float>();
//定义一个 可以容纳12个整数的整型数组 用于装载 每样产品的点击数
int[] intQuantity = new int[12];

/// <summary>
/// 记录并打印每项水果的花费
/// </summary>
/// <param name="i">物品的索引</param>
public void printCost(int i)
{
intQuantity[i]++;
lstMenu.Items.Add("您购买了\t" + productList[i].Name + "\t " + productList[i].Price + "元/斤");
TotalCost.Add(productList[i].Price);
}

/// <summary>
/// 实现所有水果按钮单击事件下触发的打印花费的方法
/// </summary>
private void FruitClick()
{
//每个按钮下 都调用了一个 printCost();方法
//传入的整型参数 是购物品在TotalCost集合里的位置 同时也是intQuantity的索引位置
btnApple.Click += (s, e) => { printCost(0); };
btnOrange.Click += (s, e) => { printCost(1); };
btnPear.Click += (s, e) => { printCost(2); };
btnbanana.Click += (s, e) => { printCost(3); };
btnHawthorn.Click += (s, e) => { printCost(4); };
btnHoneyPeach.Click += (s, e) => { printCost(5); };
btnCoconut.Click += (s, e) => { printCost(6); };
btnFig.Click += (s, e) => { printCost(7); };
btnGrape.Click += (s, e) => { printCost(8); };
btnLitchi.Click += (s, e) => { printCost(9); };
btnPlum.Click += (s, e) => { printCost(10); };
btnPomelo.Click += (s, e) => { printCost(11); };
}

/// <summary>
/// 计算总共花费
/// </summary>
private void GetTotalCost()
{
//遍历 TotalCost里所有的值 全部加起来
float tCost = 0;
foreach (float cost in TotalCost)
{
tCost += cost;
}
lstMenu.Items.Add("------------------------");
lstMenu.Items.Add("优惠前总价为:\t\t " + Math.Round(tCost, 1) + "元"); //打印出总价(打折前的价格)
//调用Saving()方法 计算 总共节省的钱数
float totalSaving = Saving();
lstMenu.Items.Add("打折后最终您需要付款为\t " + Math.Round((tCost - totalSaving), 1) + "元");
}

float tSaving = 0;
/// <summary>
/// 计算优惠额
/// </summary>
/// <returns>优惠额</returns>
public float Saving()
{
for (int i = 0; i <= intQuantity.Length - 1; i++)
{ //当物品 购买数 >= 2的时候 才有优惠
if (intQuantity[i] >= 2)
{ //这里 苹果和无花果 是不存在优惠的
if (productList[i].Name == "苹果" || productList[i].Name == "无花果")
lstMenu.Items.Add("您购买了" + productList[i].Name + " 一共" + intQuantity[i] + "斤" + " 最近" + productList[i].Name + "无优惠");
else //否则其他水果 都有优惠
{
lstMenu.Items.Add("您购买了" + productList[i].Name + " 一共" + intQuantity[i] + "斤" + " 优惠" + Math.Round(productList[i].save(intQuantity[i]), 1) + "元");
tSaving += productList[i].save(intQuantity[i]);
}
}
//当购买单项 水果 小于2斤的时候 是没有优惠享受的
else if (1 <= intQuantity[i] && intQuantity[i] < 2)
{
lstMenu.Items.Add("您购买了" + productList[i].Name + " 只有" + intQuantity[i] + "斤" + " 没有优惠!");
}
}
//最终 打印出 所有物品节约的 总价
lstMenu.Items.Add("--------------------------------------");
lstMenu.Items.Add("所有水果一共优惠了\t " + tSaving + "元");

return tSaving;//返回优惠额
}

/// <summary>
/// 清空购物车
/// </summary>
private void EmptyShoppingBox()
{
lstMenu.Items.Clear(); //清空listMenu控件里面的所有项(表面清除)
TotalCost.Clear(); //清空TotalCost里的所有项(从系统中移除)
tSaving = 0; //把之前节省的钱 全部清空
//清空的时候 要将打折省去的钱数 也清掉
//这里用的是 清空所有购买水果的数量 当水果数为0的时候 就没有打折省去的钱数了
for (int i = 0; i < intQuantity.Length; i++)
intQuantity[i] = 0;
}

/// <summary>
/// 删除已购买的单项物品
/// </summary>
private void DeleteOneShoppingItem()
{
//从listbox 里移除 购买项 (表面移除, 实际值需要从装载值的TotalCost集合里移除)
lstMenu.Items.Remove(lstMenu.SelectedItem);
//SelectedIndex 是从0开始的索引 但实际你删除项的索引是大于0的整数
//从TotalCost里移除购买项
TotalCost.RemoveAt(lstMenu.SelectedIndex + 1);
}
}

运行效果 如下

1.结账

img

2.清空购物车

img

3.再点结账 看下 确实所有值 都被清空了 (清空购物车功能 没问题)

img

\4. 但是删除单项 这里出问题了 请看下面

img

5 删除2项 山楂后 总价虽然正常减少了 而且原先买了3斤山楂 现在删除了2斤山楂 剩1斤

应该是没有优惠了 但这里还是保持原先 买3斤时候的优惠

而且总优惠价格 也是不但没减少 还把之前的再次相加了一次 导致最终价格不正常 (可能还有一些问题没有发现)

img

这里思路是有 就是 根据删除项在listbox里的索引 相对应的也是在用来装载所有购买物品价格的泛型list(TotalCost)的索引

但是 怎样判断这个索引是哪个物品呢 这里是关键.

由于这里涉及到的判断比较多 个人能力有限 还请 对该程序感兴趣的大牛们 帮忙解决下

谢了! :)

这里附上源代码 水果店结账系统 点击下载

转自:https://www.cnblogs.com/longwu/archive/2011/12/20/2294297.html