赞
踩
文本文件提供票的信息,车次、票价、始发站终点站、票数
启动程序,首先读取文件,放入TextArea中,如果车次较多,那么需要加滚动条(上述两步骤,用到的是文件读写IO)
输入车次,查找该车次,并显示信息
如何在文本域中找出相关信息,并且读出这一条信息——字符串操作
找到车次了,输入购买张数,点击购买,弹出新的窗口——新的窗口是启动了一个线程——多线程
在购买界面,显示购买车次的信息,和顾客进行确认。并且提供身份证信息
如果买多张,那么这些身份证信息,先保存到集合中(map),遍历集合,给每个身份证购买一张票
输出购买信息
需要创建一个车票javaBean类,和顾客javaBean类
来存储对应的车票信息和顾客信息
【车次.txt】用来存储车票的信息
【Person类】用来根据顾客的信息生成顾客的对象
【Ticket类】生成车票的对象
【Person类】【Ticket类】都是两个JavaBean类
存储车票信息的.txt文件
K1528 石家庄 北 京 24.2 1
K1527 北 京 石家庄 24.2 2
K1526 石家庄 北 京 24.2 100
K1525 北 京 石家庄 24.2 200
K1524 石家庄 北 京 24.2 100
K1523 北 京 石家庄 24.2 200
K1522 石家庄 北 京 24.2 100
K1521 北 京 石家庄 24.2 200
用来根据顾客的信息生成顾客的对象
public class Person { private String name; // 姓名 private String IDCard; // 身份证号 private String ticketname; // 车票名 private String start; // 起始站 private String end; // 终点站 private double price; // 车票的价钱 public Person() { super(); } public Person(String name, String iDCard) { super(); this.name = name; IDCard = iDCard; } public Person(String name, String iDCard, String ticketname, String start, String end, double price) { super(); this.name = name; IDCard = iDCard; this.ticketname = ticketname; this.start = start; this.end = end; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getIDCard() { return IDCard; } public void setIDCard(String iDCard) { IDCard = iDCard; } public String getTicketname() { return ticketname; } public void setTicketname(String ticketname) { this.ticketname = ticketname; } public String getStart() { return start; } public void setStart(String start) { this.start = start; } public String getEnd() { return end; } public void setEnd(String end) { this.end = end; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Person [name=" + name + ", IDCard=" + IDCard + ", ticketname=" + ticketname + ", start=" + start + ", end=" + end + ", price=" + price + "]"; } }
生成车票的对象
public class Ticket { private String checi; // 车票名 private String start; // 起始站 private String end; // 终点站 private double price; // 价格 private int number; // 数量 public Ticket(String checi, String start, String end, double price, int number) { super(); this.checi = checi; this.start = start; this.end = end; this.number = number; this.price = price; } public Ticket(String checi, double price, int number) { super(); this.checi = checi; this.price = price; this.number = number; } @Override public String toString() { return "Ticket [checi=" + checi + ", start=" + start + ", end=" + end + ", price=" + price + ", number=" + number + "]\n"; } public String getCheci() { return checi; } public void setCheci(String checi) { this.checi = checi; } public String getStart() { return start; } public void setStart(String start) { this.start = start; } public String getEnd() { return end; } public void setEnd(String end) { this.end = end; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } }
还需要弄个窗口显示信息,这里GUI用的Ecplise的【WindowsBuilder】
窗口的布局用的是【ABsolute layout】
控件拖动到界面就行了,进行调整一下就行了
界面创建好之后,就需要添加对应的事件监听器了
窗口加载就显示出车票信息
/** * 窗口加载事件 */ addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { FileReader fr = null; BufferedReader br = null; try { // 1.用IO流读取【车次.txt】文件的信息 fr = new FileReader(new File("src\\buyticket\\车次.txt")); br = new BufferedReader(fr); String checi = " 车 次 起始站 终点站 单价 票数\n"; String str = null; while ((str = br.readLine()) != null) { // 2.拼接字符串,用来在textArea中展示信息 checi += " " + str + "\n"; // 3.拆分字符串得到信息,创建 Ticket 对象 String[] split = str.split("\t"); Ticket tic = new Ticket(split[0], split[1], split[2], Double.parseDouble(split[3]), Integer.parseInt(split[4])); // 4.将生成的车票对象添加到 Map 集合里存储,Key-车次,Value-Ticket对象 ticketMap.put(tic.getCheci(), tic); } // 5.textArea显示步骤 2得到的拼接字符串 textArea.append(checi); } catch (Exception e1) { e1.printStackTrace(); } finally { try { br.close(); } catch (IOException e2) { e2.printStackTrace(); } try { fr.close(); } catch (IOException e2) { e2.printStackTrace(); } } } });
根据文本框输入的信息查找相关车次
/** * 查找按钮监听事件 */ button_search.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent arg0) { // 1.清空textArea_1显示的信息 textArea_1.setText(""); // 2.获取文本框输入的信息 String search = searchText.getText(); String checi = " 车 次 起始站 终点站 单价 票数\n"; // 3.遍历Map集合,比对信息 Set<Map.Entry<String, Ticket>> entrySet = ticketMap.entrySet(); for (Map.Entry<String, Ticket> entryset : entrySet) { // 3.1根据Map的键组成的集合比对从文本框得到的信息,如果Key包含有文本框的信息则获取对应的Value值,Ticket的对象 if (entryset.getKey().contains(search)) { String key = entryset.getKey(); Ticket tic = (Ticket) ticketMap.get(key); // 4.字符串拼接获取车票的信息 checi += " " + tic.getCheci() + " " + tic.getStart() + " " + tic.getEnd() + " " + tic.getPrice() + " " + tic.getNumber() + "\n"; } } // 5.textArea_1显示拼接的字符串 textArea_1.append(checi); } });
刷新车票信息的变化
/** * 刷新 */ shuaxin.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent arg0) { //1.将textArea显示的信息清空 textArea.setText(""); String checi = " 车 次 起始站 终点站 单价 票数\n"; //2.遍历Map集合,获取Map中存储的车票信息 Set<Map.Entry<String, Ticket>> entrySet = ticketMap.entrySet(); for (Map.Entry<String, Ticket> set : entrySet) { Ticket tic = (Ticket) ticketMap.get(set.getKey()); //3.字符串拼接 checi += " " + tic.getCheci() + " " + tic.getStart() + " " + tic.getEnd() + " " + tic.getPrice() + " " + tic.getNumber() + "\n"; } //4.textArea显示拼接之后的字符串 textArea.append(checi); } });
注:这里可以优化下,自动定时刷新
点击购买则弹出一个新的窗口【购买窗口】,这里就需要用到多线程,实现多个窗口同时运行
/**
* 点击购买
*/
button_buy.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent arg0) {
//创建新的线程
PayWindow pw = new PayWindow(ticketMap);
new Thread(pw).start();
}
});
和主窗口【Window类】一样,首先用【WindowBuilder】进行布局
布好局之后就可以加事件监听了
public class PayWindow extends JFrame implements Runnable {
@Override
public void run() {
PayWindow frame = new PayWindow(ticketMap);
frame.setVisible(true);
}
}
注:
这里为什么不用继承【Thread类】来实现线程类,大家可以知道,【PayWindow类】已经继承了【JFrame类】就不能再继承了,但是我们可以通过实现接口【Runnable】来实现线程类,这就是【Thread类】和【Runnable接口】在应用时的区别
每提交一次有效信息则添加一次信息
因为每个人的身份证号是唯一的,姓名可以重复,因此Map集合采用身份证号为Key,如果身份证号有重复则覆盖
textArea显示的信息中身份证号部分采用字符串截取
/** * 提交按钮 */ btnNewButton_subbmit.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent arg0) { // private String personlist1 = " 已提交信息名单\n 姓名 身份证号\n"; // 1.设置textArea显示 personlist1 字符串,因为频繁使用,所以设置成了全局变量 textArea.setText(personlist1); // 2.获取输入的姓名和身份证号 String name = textField_name.getText(); String IDCard = textField_IDCard.getText(); String li = ""; // 如果两个文本框不为空则添加信息到队列 if (!"".equals(name) && !"".equals(IDCard)) { // 3.1用获取到的姓名和身份证号生成对象,添加到存储顾客对象的Map集合中 if(name.length()<=2) { name=name.charAt(0)+" "+name.charAt(1); } Person person = new Person(name, IDCard); personMap.put(IDCard, person); } else { JOptionPane.showMessageDialog(null, name + IDCard + "信息不完整", name + IDCard, 0); } // 4.遍历Map集合,获取集合中顾客的所有信息 Set<Map.Entry<String, Person>> set = personMap.entrySet(); Iterator<Entry<String, Person>> setItor = set.iterator(); while (setItor.hasNext()) { Person person = setItor.next().getValue(); // 4.1将顾客的所有的信息拼接成字符串 li += " " + person.getName() +" " + person.getIDCard().substring(0, 6) + "******" + person.getIDCard().substring(14) + "\n"; } // 5.textArea显示拼接的字符串 textArea.append(li); } });
/** * 下单按钮 */ btnNewButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent arg0) { // 获取文本框输入的车次 String checi = textField.getText(); // 1.判断顾客选择的车次存不存在 Ticket ticket = (Ticket) ticketMap.get(checi); if (ticket != null) { // 2. 判断是否添加顾客的信息 int number = personMap.size(); if (number > 0) { JOptionPane.showMessageDialog(null, "已提交信息名单为" + number, "已提交信息", 1); // 获取车次的信息 String name = ticket.getCheci(); String end = ticket.getEnd(); String start = ticket.getStart(); double price = ticket.getPrice(); int ticketNumber = ticket.getNumber(); // 用来接收对话框的返回值 int n = 0; // 3.判断车票数量是否小于购买数量 if (ticketNumber < number) { n = JOptionPane.showConfirmDialog(null, "车票剩余不够购买数量,目前剩余数量:" + ticketNumber + ",如果继续购买则先买先得", "", JOptionPane.YES_NO_OPTION); } if (n == 0) { // 4.支付 int a = JOptionPane.showConfirmDialog(null, "按照已提交信息名单收取金额(若未购买到票则退还相应的金额),应支付金额:" + personMap.size() * price + ",是否确认支付", "支付窗口", JOptionPane.YES_NO_OPTION); if (a == 0) { JOptionPane.showMessageDialog(null, "支付成功", checi, 1); textArea.setText(personlist2); String jine = ""; // 5.购票 同步购票代码块, synchronized (PayWindow.class) { boolean bool = true; if (ticketNumber == 0) { bool = false; } // 统计购买了多少张票 int count = 0; // 根据输入的信息循环购买多张票,如果票不够,则买完为止 Set<Map.Entry<String, Person>> set = personMap.entrySet(); Iterator<Entry<String, Person>> setItor = set.iterator(); for (int i = 1; i <= personMap.size(); i++) { if (bool) { // 5.1修改票的信息 Ticket tic = new Ticket(name, start, end, price, --ticketNumber); count++; if (setItor.hasNext()) { Person person = setItor.next().getValue(); person.setTicketname(name); person.setPrice(price); } Window.ticketMap.put(name, tic); } jine = count * price + ""; // 5.2如果车票卖完,但是还有顾客没买到票,则退钱 if (ticketNumber == 0) { bool = false; ticketMap.remove(ticket.getCheci()); JOptionPane.showMessageDialog(null, "票已售完,返还" + (personMap.size() - count) * price + "总共花费" + count * price, "支付窗口", 1); break; } } } // 6.输出所有顾客信息 Set<Map.Entry<String, Person>> set = personMap.entrySet(); Iterator<Entry<String, Person>> setItor = set.iterator(); String li = ""; while (setItor.hasNext()) { Person person = setItor.next().getValue(); // 截取字符串显示******** li += " " + person.getName() + " " + person.getIDCard().substring(0, 6) + "*******" + person.getIDCard().substring(14) + " " + person.getTicketname() + " " + person.getPrice() + "\n"; } textArea.append(li); textArea.append(" 总共花费:" + jine); // 7.清空集合,以便下次提交信息 personMap.clear(); } else { JOptionPane.showMessageDialog(null, "支付失败", checi, 0); } } else { JOptionPane.showMessageDialog(null, checi + "票不够", checi, 0); } } else { JOptionPane.showMessageDialog(null, "未添加信息", checi, 0); } } else { JOptionPane.showMessageDialog(null, "未找到" + checi, checi, 0); } } });
关闭购票窗口而不关闭整个程序
// 设置窗口销毁,而不关闭程序
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
dispose();
}
});
导入之后,更改导入包以及【车次.txt】文件路径
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。