我希望能得到更多的建议,如果你觉得哪里能够改进,请您花点时间告诉我,
QQ:1743703238
独立网站:www.addoiles.com
电台:《程序员的生活记录》 目前在网易云音乐/网易云电台,荔枝FM,喜马拉雅,苹果播客可获得收听
影院购票系统实现的功能:
1.选择电影
2.该电影有放映场次,可以选择放映场次
3.电影中提供三种票:学生票、普通票、赠送票
4.电影选好了、时间选好了、票的种类选好了,就可以选座位了
5.有确认购票的功能,票才会买,而且你的票一旦买过就不能重复买
6.当你换到其他的时间场次,可以购票,再回来时,购票的信息还在,就是保存死了,不会丢失
7.当你关闭系统时,再次打开信息时票的信息还在
8.提供了系统重置的功能,一旦重置,所有的东西全部初始化
Movie的XML文件:
<?xml version="1.0" encoding="utf-8" ?>
<ShowList>
<Movie>
<Name>碟中谍5</Name>
<Poster>碟中谍5.jpg</Poster>
<Director>克里斯托夫·迈考利</Director>
<Actor>汤姆·克鲁斯 / 杰瑞米·雷纳</Actor>
<Type>动作、冒险、惊悚</Type>
<Price>60</Price>
<Schedule>
<item>9:00</item>
<item>12:50</item>
</Schedule>
</Movie>
<Movie>
<Name>地心引力</Name>
<Poster>地心引力.jpg</Poster>
<Director>阿方索·卡隆</Director>
<Actor>乔治·克鲁尼 / 桑德拉·布洛克</Actor>
<Type>科幻 / 剧情 / 惊悚</Type>
<Price>80</Price>
<Schedule>
<item>12:00</item>
<item>15:00</item>
</Schedule>
</Movie>
<Movie>
<Name>极乐空间</Name>
<Poster>极乐空间.jpg</Poster>
<Director>尼尔·布洛姆坎普</Director>
<Actor>马特·达蒙 / 朱迪·福斯特</Actor>
<Type>科幻 / 动作 / 剧情</Type>
<Price>60</Price>
<Schedule>
<item>7:00</item>
<item>12:20</item>
<item>15:30</item>
</Schedule>
</Movie>
<Movie>
<Name>星际穿越</Name>
<Poster>星际穿越.jpg</Poster>
<Director>克里斯托弗·诺兰</Director>
<Actor>马修·麦康纳 / 安妮·海瑟薇</Actor>
<Type>冒险 / 科幻</Type>
<Price>90</Price>
<Schedule>
<item>1:00</item>
<item>2:23</item>
</Schedule>
</Movie>
<Movie>
<Name>遗落战境</Name>
<Poster>遗落战境.jpg</Poster>
<Director>约瑟夫·科辛斯基</Director>
<Actor>汤姆·克鲁斯 / 摩根·弗里曼</Actor>
<Type>科幻 / 冒险 / 悬疑 / 动作</Type>
<Price>80</Price>
<Schedule>
<item>1:20</item>
<item>2:34</item>
</Schedule>
</Movie>
<Movie>
<Name>泰坦尼克号</Name>
<Poster>泰坦尼克号.jpg</Poster>
<Director>詹姆斯·卡梅隆</Director>
<Actor>迪卡普里奥/温斯莱特</Actor>
<Type>灾难,爱情</Type>
<Price>80</Price>
<Schedule>
<item>1:45</item>
<item>2:14</item>
</Schedule>
</Movie>
</ShowList>
Form1窗体中的源代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;
namespace FetchMovie
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
LoadTreeView(); //加载TreeView
LoadLabel();//加载座位Label
this.cboDiscount.Items.Add("今天全免费!!!");
this.cboDiscount.SelectedIndex = 6;
}
/// <summary>
/// 成员变量
/// </summary>
public string xmlPath = "C:\\Users\\YangRunkang\\Desktop\\FetchMovie\\FetchMovie\\Movie.xml";
public int ticketsCount = 0;//定的座位的个数,及买票的个数,要保证每次换是时间时,就是选别的时间看电影,要归0,但在归0之前,要存起来
public bool isBuy=false;//是否选择电影(即是否触发了TreeView的AfterSelect事件),如果触发了该事件,true
public string ticketType = "";//电影票的类型
public double totalMoney = 0;//总票价
public StringBuilder seatNumber = new StringBuilder();//记录座位号
public List<Label> LabelLists = new List<Label>();//记录界面中的所有座位Label
public string otherPeople = "匿名";//增票的人的名字
//public int isTreeViewClick = 0;
/// <summary>
/// 加载座位的Label标签
/// </summary>
public void LoadLabel()
{
for (int i = 1; i <=5;i++)//控制行数
{
for (int n = 1; n <=7; n++)
{
Label label = new Label();
label.Location = new Point(60+(i*100),-20+(n*50));
label.Text = (n.ToString() + "-" + i.ToString()).ToString();
label.TextAlign = ContentAlignment.MiddleCenter;
label.Size = new System.Drawing.Size(50,25);
label.BackColor = Color.Wheat;
label.Tag = (i.ToString() + n.ToString()).ToString();//只以此为唯一标示 label
label.Click += new EventHandler(label18_Click);//绑定统一事件
this.tabPage2.Controls.Add(label);
LabelLists.Add(label);//将new出来的Label存入总的List<Class>中,以备不时之需
}
}
}
/// <summary>
/// 加载TreeView
/// </summary>
public void LoadTreeView()
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
XmlNode node = doc.DocumentElement;
foreach (XmlNode no in node.ChildNodes)
{
foreach (XmlNode n in no.ChildNodes)
{
//电影名称节点 父节点
TreeNode MasterNode = new TreeNode();
MasterNode.Text = no["Name"].InnerText;
MasterNode.Tag = MasterNode;//Save Node
this.treeView1.Nodes.Add(MasterNode);
//时间节点,统一以电影名称节点为父节点
TreeNode StuNode = new TreeNode();
StuNode.Text=no["Schedule"]["item"].InnerText;
StuNode.Tag = StuNode;
MasterNode.Nodes.Add(StuNode);//加载到父节点MasterNode下
//时间节点,统一以电影名称节点为父节点
TreeNode StuNode2 = new TreeNode();
StuNode2.Text = no["Schedule"]["item"].NextSibling.InnerText;//判断点 下
StuNode2.Tag = StuNode2;
MasterNode.Nodes.Add(StuNode2);//加载到父节点MasterNode下
break;//循环一次,跳一次
}
}
}
/// <summary>
/// 统一公用的控件,此控件的点击事件绑定了35个new出来的控件
/// </summary>
/// <param name="sender">点击label控件时,一个对象就穿过来了</param>事件源
/// <param name="e"></param>
//定义一个Label集合,里面存入已经售出的票
List<Label> labelList = new List<Label>();
private void label18_Click(object sender, EventArgs e)
{
Label clickLabel =(Label)sender;
//售出的,不能再卖
if (clickLabel.BackColor == Color.Red)
{
MessageBox.Show("此票以售出");
return;
}
clickLabel.BackColor = Color.Red;//点击后,变色
string text = clickLabel.Text;//我点击的Label上的Text值
//座位号
seatNumber.Append(text+"\t");//座位号如果有多个的话,他是追加的
labelList.Add(clickLabel);
ticketsCount++;//用加加,原来问题是处在这里,不是算你点了多少个label,而是算你实际的有效点击次数
//ticketsCount = labelList.Count;//记票数
}
//定义一个数组这个数组中存入电影的名字 然后用循环一次查找,找到即显示相应的图片 然后return
//找不到,就什么都不干
string[] filmNames = new string[] { "碟中谍5", "地心引力", "极乐空间", "星际穿越", "遗落战境", "泰坦尼克号"};
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
//每一次点击保证所有的座位Label是最新的,新场次嘛,肯定要最新的;也要保证座位号(我是把它设为全局变量)是全新的,
//不能在上一次的基础上追加
foreach(Label label in LabelLists)
{
label.BackColor = Color.Wheat;
seatNumber = new StringBuilder() ;
this.lowPrice.Text = "无优惠";//将优惠价重置
this.txtSender.Text = "匿名";//将赠送者的文本框重置
ticketsCount = 0;//我换场次的时候,票数也要归0
}
// 点击相应的电影显示相应的图片
for (int i = 0; i < filmNames.Length;i++)
{
//一开始用 this.treeView1.SelectedNode.Tag.ToString().Substring(9) 用了Tag,其实弄麻烦了,直接用text
if ((this.treeView1.SelectedNode.Text.ToString()).Equals(filmNames[i]))
{
//MessageBox.Show("TestOK");测试成功,能实现
this.pictureBox1.BackgroundImage=this.Poster.Images[i];
this.pictureBox1.BackgroundImageLayout = ImageLayout.Stretch;
//return;不能再这里return,在这里return将结束这个方法,那么下面的将不会执行
}
}
//进来就说明你点了电影,
isBuy = true;
TreeNode node= this.treeView1.SelectedNode;//你选中的节点,电影节点(第2次的想法)
//node.Text;//节点上的文本信息
string cinemaName = node.Text;//获取具体的电影,然后就可以展示了
showDetailsByName(node, cinemaName);
//如果当前节点下面有字节点,那么我就打开
if (node.Nodes.Count>0)
{
node.Expand();//因为我是点击节点,然后就顺便,所以其子节点是可见的
}
//处理点击时间,放映时间也会变得功能
if (node.Nodes.Count == 0) //等于0说明我选的是时间
{
TreeNode childNode = this.treeView1.SelectedNode;//因为此子节点下面就没有其他节点了,所以就是时间了
this.Time.Text = childNode.Text;
}
///触发条件 深度为1 次判断,用于根据节点获取相应的获取文件,并从文件中获取数据,最后将获取到到的数据还原到窗体上
if (this.treeView1.SelectedNode.Level == 1)
{
DealTxtToForm();
}
}
/// <summary>根电影的名字来展示电影的相关信息
/// 根电影的名字来展示电影的相关信息
/// </summary>
/// <param name="node">选中的节点(电影名称的节点)</param>
/// <param name="cinemaName">选中节点上的文本,即电影的名字</param>
public void showDetailsByName(TreeNode node,string cinemaName)
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
XmlNode no = doc.DocumentElement;
foreach (XmlNode n in no.ChildNodes)
{
if (n["Name"].InnerText.Equals(cinemaName))
{
// MessageBox.Show("1234");测试成功,所以下面就好办了,给各个空间赋值
this.FileName.Text=cinemaName;
this.Director.Text = n["Director"].InnerText;
this.Actor.Text = n["Actor"].InnerText;
this.Type.Text = n["Type"].InnerText;
this.Price.Text = n["Price"].InnerText;
}
}
}
/// <summary>
/// 购票条件: 选票 选座位 根据票的种类计算价格,最后打印,打印前或后将数据存入文件
/// 购票流程: 流程用字符串进行记录,每记录一个信息用一个%进行结尾,最后以%为标志,进行分割,然后存入数组,以供使用
/// 1.选电影 public bool isBuy
/// 2.选座位 public int ticketsCount
/// 3.选票 rbtn
/// 4.最后点击“购票”按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void 购票ToolStripMenuItem_Click(object sender, EventArgs e)
{
buyTicketBefore();//里面调用了购票方法buyTicket(),在调用这个方法之前,就是先判断用户是否买票
seatNumber = new StringBuilder(); //卖完之后,我要将seatNumber座位号清空一下,调试的结果 测试成功
}
/// <summary>
/// 买之前要进行一定的价检查,价差好了之后再调用buyTicket()方法,进行买票
/// </summary>
public void buyTicketBefore()
{
//判断用户选择,已提供良好的用户体验
//Cool
if (this.treeView1.SelectedNode == null)//判断节点对象是否为空,就可以判断有没有选择,不用凭借字符字符了,而且凭借字符效率也好低
{
MessageBox.Show("请选择电影");
return;
}
else if (this.treeView1.SelectedNode.Parent == null)
{
MessageBox.Show("请选择时间");
return;
}
else if (ticketsCount == 0)
{
MessageBox.Show("请选择座位");
return;
}else if (this.rbtnNormal.Checked == false && this.rbtnSend.Checked == false && this.rbtnStu.Checked == false) //判断 票的种类 有没有选
{
MessageBox.Show("请选择票的种类");
return;
}
else
{
//先问是否购买
DialogResult result = MessageBox.Show("是否确认购买", "友情提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
buyTicket(); //当一切ok,没错,那么我们进行购票 调用buyTicket()
}
else //不买,将选的座位空出来
{
//定义一个Label的List集合,里面存入已经售出的票 List<Label> labelList = new List<Label>();
//将存在集合里面的票颜色变过来
foreach (Label label in labelList)
{
label.BackColor = Color.Wheat;
}
ticketsCount = 0;
}
}
}
/// <summary>
/// 购票的方法
/// </summary>
public void buyTicket()
{
string selectTime = this.treeView1.SelectedNode.Text.Replace(":","");//因为时间有:,而:作为文件名就不行就会从出错
string path = "d:\\" + this.treeView1.SelectedNode.Parent.Text + "%" + selectTime + ".txt";
//文件流
FileStream fis = new FileStream(path, FileMode.Create);
//写入器
StreamWriter sw = new StreamWriter(fis);
//写
//
//this.treeView1.SelectedNode.Parent.Text 电影名称
//this.treeView1.SelectedNode.Text 电影的放映时间
//ticketsCount 电影的票数
//
StringBuilder sb = new StringBuilder();//电影清单
sb.AppendLine("********************************");
sb.AppendLine("*********影院售票系统*********");
sb.AppendLine("电影名称:《" + this.treeView1.SelectedNode.Parent.Text + "》");
sb.AppendLine("电影放映时间:" + this.treeView1.SelectedNode.Text + "");
sb.AppendLine("电影类型:" + this.Type.Text + "");
sb.AppendLine("购买《" + this.treeView1.SelectedNode.Parent.Text + "》电影票数量:" + ticketsCount.ToString() + "张");
//处理学生票类型
string ticketType="";
if(this.rbtnNormal.Checked==true)
{
ticketType="普通票";
}else if(this.rbtnSend.Checked==true)
{
ticketType="赠送票";
}else
{
ticketType="学生票";
}
sb.AppendLine("电影票类型:" + ticketType);
if ((!this.txtSender.Text.Equals("匿名"))||!(this.txtSender.Text.Equals(string.Empty)))//表示有人送票,然后将赠送票的人打印出来
{
sb.AppendLine("赠送者:"+this.txtSender.Text);
}
//如果我选的是普通票,我算一下;赠送不用算0元,学生票已经处理过了//test OK全成功
if( ticketType=="普通票")
{
totalMoney = Convert.ToInt32(this.Price.Text) * ticketsCount;
ticketsCount = 0;//每次算完各自的账后,就归0,反正已经用过了
}
sb.AppendLine("总票价:"+totalMoney);
totalMoney = 0;//用完之后就清0,给下一个操作留位子 //Test OK
//**************************打印座位号
sb.AppendLine("您的座位号是:"+seatNumber.ToString());
sb.AppendLine("购票时间:" + System.DateTime.Now.ToString());
sb.AppendLine("********************************"); sw.Write(sb.ToString());//向文件中写入
//关闭
sw.Close();
fis.Close();
MessageBox.Show(sb.ToString());
}
/// <summary>
/// 当选的是学生票是,学生折扣的cbo能用
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void rbtnStu_CheckedChanged(object sender, EventArgs e)
{
this.cboDiscount.Enabled = true;
this.txtSender.Text = "";
ticketType = "学生票";
this.txtSender.Enabled = false;
this.lowPrice.Text = "¥";
}
//普通票
private void rbtnNormal_CheckedChanged(object sender, EventArgs e)
{
this.cboDiscount.Enabled = false;
this.txtSender.Enabled = false;
this.txtSender.Text = "";
this.lowPrice.Text = "无优惠";
ticketType = "普通票";
}
//赠票 优惠的label改为0
private void rbtnSend_CheckedChanged(object sender, EventArgs e)
{
this.cboDiscount.Enabled = false;
this.txtSender.Enabled = true;//当点中rbtnSend时,那么txtSender可用
this.txtSender.Text = otherPeople;
this.lowPrice.Text = "赠票,价格0元" + "赠送者:" + otherPeople;
ticketType = "赠票";
}
private void txtSender_TextChanged(object sender, EventArgs e)
{
this.lowPrice.Text ="无优惠"+" "+ "赠送者:"+this.txtSender.Text;
}
/// <summary>
/// 专门处理学生票的,为学生票票计算钱的 获取总金额totalMoney
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cboDiscount_SelectedIndexChanged(object sender, EventArgs e)
{
string disCountStr=this.cboDiscount.Text;
//多个if判断麻烦,用数组
string[] dis = new string[] { "九折", "八折", "七折", "六折", "五折", "四折", "今天全免费!!!" };
double[] ToDis = new double[] { 0.9,0.8,0.7,0.6,0.5,0.4,0};//对应上面的折扣
for (int i = 0; i < dis.Length; i++)
{
if (disCountStr == dis[i])
{
totalMoney = ticketsCount * Convert.ToDouble(this.Price.Text) * ToDis[i];
this.lowPrice.Text = totalMoney.ToString();
return;
}
}
}
//艰巨的任务来了,从文件中获取数据,并且将获取到到的数据还原到窗体上 --->文本信息获取到了之后,转到另一个方法中AccordingfileContentLoadLabelOfSeat()
/// <summary>
/// 从文件中获取数据,并且将获取到到的数据还原到窗体上
///
/// 事件触发条件:节点深度为1
/// </summary>
public string fileContent = "";
public void DealTxtToForm()
{
//所有电影的文件的名称(简单点,就是买完票之后的清单) 没有枚举了,直接用数组,方便点
string[] allFilesName = new string[] { "地心引力%1200.txt", "地心引力%1500.txt", "碟中谍5%900.txt", "碟中谍5%1250.txt", "极乐空间%700.txt", "极乐空间%1220.txt", "泰坦尼克号%145.txt", "泰坦尼克号%214.txt", "星际穿越%100.txt", "星际穿越%223.txt", "遗落战境%120.txt", "遗落战境%234.txt" };
//我要获取D盘下的所有文件的文件名,然后用for循环进行依次比对,比对成功打开文件,进行文件中数据的处理
//到D盘下
DirectoryInfo D = new DirectoryInfo("D:\\");
//获取D盘下的文件
FileInfo[] D_files = D.GetFiles();
//获取每个文件的文件名 存到文件名数组中
//文件名数组
string[] getD_filesName=new string[D_files.Length];
//文件全路径数组
string[] getD_filesFullName = new string[D_files.Length];
for (int i = 0; i < D_files.Length; i++)
{
getD_filesName[i] = D_files[i].Name;
getD_filesFullName[i] = D_files[i].FullName;
}
//下面的验证成功,可以获取到文件的名称
//for (int i = 0; i < D_files.Length; i++)
//{
// MessageBox.Show(getD_filesName[i]);
// MessageBox.Show(getD_filesFullName[i]);
//}
//就是根据用户的点击(此方法的触发有一个条件,节点深度为1,所以不用担心,所以可以直接用this.treeView1.SelectNode.Text),来调取相应的文件
string treeViewSelectNodeText = this.treeView1.SelectedNode.Parent.Text + "%" + this.treeView1.SelectedNode.Text.Replace(":","") + ".txt";//时间要将:去掉
//MessageBox.Show(treeViewSelectNodeText); OK
for (int i = 0; i < D_files.Length; i++)
{
if (treeViewSelectNodeText == getD_filesName[i])//如果文件名称相等
{
FileStream fis = new FileStream(getD_filesFullName[i],FileMode.Open);//文件的全路径//打开文件获取里面的内容
StreamReader read = new StreamReader(fis);
fileContent = read.ReadToEnd();//从头读到尾,将读到的数据放入成员变量fileContent中
//MessageBox.Show(fileContent); OK
read.Close();
fis.Close();
AccordingfileContentLoadLabelOfSeat(fileContent);//专门处理座位的文本
return;
}
}
//如果if进去,下面的两行代码是执行不了的
//MessageBox.Show(treeViewSelectNodeText);
//MessageBox.Show(fileContent);
}
/// <summary>
/// 文本信息获取到了之后,根据文本的信息加载座位Label
/// </summary>
/// <param name="fileContent"></param>
//LabelLists 所有的座位号,一直存在数组里,现在到用它的时候了
public void AccordingfileContentLoadLabelOfSeat(string fileContent)
{
//下面就是处理文本了,我主要是想获取里面的座位号 X-Y 格式的
//解决方法 以"-"为标志,取前取后,然后连接起来,存入新的数组(成员变量的位置),以供使用
我现将所有的内容,分割,一个字符分一下 行不通
//string[] words = fileContent.Split(' ');
//for (int i = 0; i < words.Length; i++)
//{
// MessageBox.Show(words[i]);
//}
//正则表达式
Regex obj = new Regex("[0-9][-][0-9]");
MatchCollection co= obj.Matches(fileContent,0);
foreach(Match maco in co) //MatchCollection 大, match 小
{
//MessageBox.Show(maco.ToString()); 测试成功,每个座位号都可以获取
foreach (Label label in LabelLists)
{
if (label.Text.Equals(maco.ToString()))
{
label.BackColor = Color.Red;
}
}
}
}
private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void 重置系统ToolStripMenuItem_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("是否重置系统?", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
//所有电影的文件的名称(简单点,就是买完票之后的清单) 没有枚举了,直接用数组,方便点
string[] allFilesName = new string[] { "地心引力%1200.txt", "地心引力%1500.txt", "碟中谍5%900.txt", "碟中谍5%1250.txt", "极乐空间%700.txt", "极乐空间%1220.txt", "泰坦尼克号%145.txt", "泰坦尼克号%214.txt", "星际穿越%100.txt", "星际穿越%223.txt", "遗落战境%120.txt", "遗落战境%234.txt" };
//我要获取D盘下的所有文件的文件名,然后用for循环进行依次比对,比对成功打开文件,进行文件中数据的处理
//到D盘下
DirectoryInfo D = new DirectoryInfo("D:\\");
//获取D盘下的文件
FileInfo[] D_files = D.GetFiles();
//获取每个文件的文件名 存到文件名数组中
//文件名数组
string[] getD_filesName = new string[D_files.Length];
//文件全路径数组
string[] getD_filesFullName = new string[D_files.Length];
for (int i = 0; i < D_files.Length; i++)
{
getD_filesName[i] = D_files[i].Name;
getD_filesFullName[i] = D_files[i].FullName;
}
for (int i = 0; i < D_files.Length; i++)
{
File.Delete(getD_filesFullName[i]);
}
this.Hide();//隐藏
Form1 form = new Form1();
form.Show();//show
MessageBox.Show("重置成功");
}
}
}
}
我希望能得到更多的建议,如果你觉得哪里能够改进,请您花点时间告诉我,手机号:13955195045(发信息给我) QQ:1743703238 微博:杨润康Bla