当前位置:   article > 正文

Java使用多线程和GUI实现购买火车票<集合>_12306 java gui

12306 java gui


绪:

  • 多线程与并发
  • 集合Map 、List
  • GUI(ecplise插件WindowBuilder)

样例

image-20210415143525182


DEMO——购票项目


项目要求

  1. 文本文件提供票的信息,车次、票价、始发站终点站、票数

  2. 启动程序,首先读取文件,放入TextArea中,如果车次较多,那么需要加滚动条(上述两步骤,用到的是文件读写IO)

  3. 输入车次,查找该车次,并显示信息

    如何在文本域中找出相关信息,并且读出这一条信息——字符串操作

  4. 找到车次了,输入购买张数,点击购买,弹出新的窗口——新的窗口是启动了一个线程——多线程

  5. 在购买界面,显示购买车次的信息,和顾客进行确认。并且提供身份证信息

    如果买多张,那么这些身份证信息,先保存到集合中(map),遍历集合,给每个身份证购买一张票

  6. 输出购买信息


实现步骤

需要创建一个车票javaBean类,和顾客javaBean类

来存储对应的车票信息和顾客信息


一、【车次.txt】【Person类】【Ticket类】

  • 【车次.txt】用来存储车票的信息

  • 【Person类】用来根据顾客的信息生成顾客的对象

  • 【Ticket类】生成车票的对象

【Person类】【Ticket类】都是两个JavaBean类


1.【车次.txt】

存储车票信息的.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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.【Person类】

用来根据顾客的信息生成顾客的对象



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 + "]";
	}

}

  • 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

3.【Ticket类】

生成车票的对象



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;
	}

}

  • 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

二、主窗口 【Window类


1、界面

还需要弄个窗口显示信息,这里GUI用的Ecplise的【WindowsBuilder】

窗口的布局用的是【ABsolute layout】

控件拖动到界面就行了,进行调整一下就行了

image-20210415160826973

界面创建好之后,就需要添加对应的事件监听器了


2、事件监听
1.窗口加载就显示出信息

窗口加载就显示出车票信息

		/**
		 * 窗口加载事件
		 */
		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();
					}
				}

			}
		});
  • 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

2.查找按钮

根据文本框输入的信息查找相关车次

		/**
		 * 查找按钮监听事件
		 */
		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);
			}
		});
  • 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

3. 刷新

刷新车票信息的变化

		/**
		 * 刷新
		 */
		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);
			}
		});
  • 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

注:这里可以优化下,自动定时刷新


4.购买

点击购买则弹出一个新的窗口【购买窗口】,这里就需要用到多线程,实现多个窗口同时运行

		/**
		 * 点击购买
		 */
		button_buy.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {

				//创建新的线程
				PayWindow pw = new PayWindow(ticketMap);
				new Thread(pw).start();

			}
		});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

三、购买窗口【PayWindow类】


1、界面

和主窗口【Window类】一样,首先用【WindowBuilder】进行布局
image-20210415094406069

布好局之后就可以加事件监听了


2、实现线程接口【Runnable】
public class PayWindow extends JFrame implements Runnable {
	@Override
	public void run() {
		PayWindow frame = new PayWindow(ticketMap);
		frame.setVisible(true);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注:

这里为什么不用继承【Thread类】来实现线程类,大家可以知道,【PayWindow类】已经继承了【JFrame类】就不能再继承了,但是我们可以通过实现接口【Runnable】来实现线程类,这就是【Thread类】和【Runnable接口】在应用时的区别


3、事件监听

1.提交信息
  • 每提交一次有效信息则添加一次信息

  • 因为每个人的身份证号是唯一的,姓名可以重复,因此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);

			}
		});
  • 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

2.下单
  1. 判断顾客选择的车次存不存在
  2. 判断是否添加顾客的信息
  3. 判断车票数量是否小于购买数量
  4. 支付
  5. 购票
    1. 修改票的信息
    2. 如果车票卖完,但是还有顾客没买到票,则退钱
  6. 输出所有顾客信息
  7. 清空集合,以便下次提交信息
		/**
		 * 下单按钮
		 */
		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);
				}

			}
		});
  • 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

3.窗口销毁

关闭购票窗口而不关闭整个程序

		// 设置窗口销毁,而不关闭程序
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				dispose();
			}
		});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

源代码

Java用多线程GUI实现买车票【ticket.zip】

导入之后,更改导入包以及【车次.txt】文件路径

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/632163
推荐阅读
相关标签
  

闽ICP备14008679号