代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
public class TrainBookingSystem {
private JFrame frame;
private JPanel loginPanel, mainPanel;
private JTextField usernameField;
private JPasswordField passwordField; // 改为JPasswordField
private JTextField departureField, destinationField;
private JButton searchButton;
private List<Train> trainList;
private List<Order> paidOrders;
private List<Order> waitingListOrders;
private List<Order> myTickets;
private JPanel paidPanel, waitingListPanel, myTicketsPanel;
public TrainBookingSystem() {
frame = new JFrame("12306 Train Booking System");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
createLoginInterface();
initTrainData();
paidOrders = new ArrayList<>();
waitingListOrders = new ArrayList<>();
myTickets = new ArrayList<>();
}
private void createLoginInterface() {
loginPanel = new JPanel(new BorderLayout());
loginPanel.add(createWelcomeLabel(), BorderLayout.NORTH);
JPanel authPanel = new JPanel(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.insets = new Insets(10, 5, 10, 5);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 0;
authPanel.add(new JLabel("账号:"), constraints);
constraints.gridx = 1;
authPanel.add(usernameField = new JTextField(30), constraints);
constraints.gridx = 0;
constraints.gridy = 1;
authPanel.add(new JLabel("密码:"), constraints);
constraints.gridx = 1;
authPanel.add(passwordField = new JPasswordField(30), constraints);
JButton loginButton = new JButton("登录");
loginButton.addActionListener(e -> login());
constraints.gridx = 0;
constraints.gridy = 2;
constraints.gridwidth = 2; // 按钮横跨两列
authPanel.add(loginButton, constraints); // 移除多余的参数
loginPanel.add(authPanel, BorderLayout.CENTER);
frame.setContentPane(loginPanel);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JLabel createWelcomeLabel() {
JLabel welcomeLabel = new JLabel("欢迎使用12306订票系统");
Font font = new Font("SansSerif", Font.BOLD, 24);
welcomeLabel.setFont(font);
welcomeLabel.setHorizontalAlignment(SwingConstants.CENTER);
return welcomeLabel;
}
private void login() {
String username = usernameField.getText();
char[] passwordChars = passwordField.getPassword();
String password = new String(passwordChars);
if (!username.isEmpty() && !password.isEmpty()) {
// 登录逻辑
frame.setContentPane(createMainInterface());
frame.revalidate();
frame.repaint();
} else {
JOptionPane.showMessageDialog(frame, "请输入账号和密码!");
}
}
private JPanel createMainInterface() {
mainPanel = new JPanel(new BorderLayout());
// 左侧面板
JPanel leftPanel = new JPanel(new BorderLayout());
leftPanel.setPreferredSize(new Dimension((int)(frame.getWidth() * 0.75), frame.getHeight()));
leftPanel.setBorder(BorderFactory.createTitledBorder("车票查询"));
JPanel inputPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(10, 5, 10, 5);
gbc.gridx = 0;
gbc.gridy = 0;
inputPanel.add(new JLabel("始发站:"), gbc);
gbc.gridx = 1;
gbc.gridwidth = 2;
inputPanel.add(departureField = new JTextField(30), gbc);
gbc.gridx = 0;
gbc.gridy = 1;
inputPanel.add(new JLabel("终点站:"), gbc);
gbc.gridx = 1;
inputPanel.add(destinationField = new JTextField(30), gbc);
searchButton = new JButton("车次查询");
searchButton.addActionListener(e -> showTrainList());
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 3;
inputPanel.add(searchButton, gbc);
leftPanel.add(inputPanel, BorderLayout.CENTER);
// 右侧面板
JPanel rightPanel = new JPanel(new GridLayout(3, 1)); // 3行1列的网格布局
rightPanel.setPreferredSize(new Dimension(frame.getWidth() / 4, frame.getHeight()));
rightPanel.setBorder(BorderFactory.createTitledBorder("个人订单查询"));
// 初始化面板并添加到右侧面板
paidPanel = new JPanel(new FlowLayout());
waitingListPanel = new JPanel(new FlowLayout());
myTicketsPanel = new JPanel(new FlowLayout());
// 订单管理按钮初始化并添加到右侧面板
JButton paidOrdersButton = new JButton("已支付");
paidOrdersButton.addActionListener(e -> showOrders(paidOrders));
rightPanel.add(paidOrdersButton, BorderLayout.NORTH);
// 注意:需要将候补订单按钮添加到面板上
JButton waitingListOrdersButton = new JButton("候补订单");
waitingListOrdersButton.addActionListener(e -> showOrders(waitingListOrders));
// 将候补订单按钮添加到rightPanel中
rightPanel.add(waitingListOrdersButton, BorderLayout.CENTER);
JButton myTicketsButton = new JButton("本人车票");
myTicketsButton.addActionListener(e -> showOrders(myTickets));
rightPanel.add(myTicketsButton, BorderLayout.SOUTH);
rightPanel.add(new JLabel(" "), BorderLayout.CENTER);
mainPanel.add(leftPanel, BorderLayout.CENTER);
mainPanel.add(rightPanel, BorderLayout.EAST);
// 初始订单显示更新
updateOrderDisplays();
return mainPanel;
}
private void showOrders(List<Order> orders) {
if (orders.isEmpty()) {
JOptionPane.showMessageDialog(frame, "当前没有订单!");
} else {
String message = "订单信息:\n";
for (Order order : orders) {
message += order.toString() + "\n";
}
JOptionPane.showMessageDialog(frame, message, "订单列表", JOptionPane.INFORMATION_MESSAGE);
}
}
private void showTrainList() {
JDialog dialog = new JDialog(frame, "车次列表", true);
dialog.setLayout(new BorderLayout());
dialog.setSize(400, 300);
JPanel trainInfoPanel = new JPanel(new GridLayout(trainList.size(), 1));
for (Train train : trainList) {
JPanel trainPanel = new JPanel(new BorderLayout());
JButton bookButton = new JButton("订票");
JButton waitlistButton = new JButton("候补");
waitlistButton.setVisible(false);
bookButton.addActionListener(evt -> {
if (train.book()) {
addOrder(train, true); // 订票成功
JOptionPane.showMessageDialog(frame, "订票成功!");
dialog.dispose();
} else {
waitlistButton.setVisible(true);
}
});
waitlistButton.addActionListener(evt -> {
addOrder(train, false); // 候补票
JOptionPane.showMessageDialog(frame, "候补成功!");
dialog.dispose();
});
trainPanel.add(new JLabel(train.getTrainNumber() + " - " + train.getDepartureTime() + " - 剩余票数:" + train.getRemainingSeats()), BorderLayout.CENTER);
JPanel buttonPanel = new JPanel(new FlowLayout());
buttonPanel.add(bookButton);
buttonPanel.add(waitlistButton);
trainPanel.add(buttonPanel, BorderLayout.EAST);
trainInfoPanel.add(trainPanel);
}
JScrollPane scrollPane = new JScrollPane(trainInfoPanel);
dialog.add(scrollPane, BorderLayout.CENTER);
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
private void addOrder(Train train, boolean isPaid) {
Order order = new Order(train, isPaid);
if (isPaid) {
paidOrders.add(order);
myTickets.add(order);
} else {
waitingListOrders.add(order);
}
updateOrderDisplays();
}
private void updateOrderDisplays() {
// 此处不再需要removeAll,因为面板已经初始化
paidPanel.removeAll();
waitingListPanel.removeAll();
myTicketsPanel.removeAll();
// 直接添加订单信息
for (Order order : paidOrders) {
paidPanel.add(new JLabel(order.toString()));
}
for (Order order : waitingListOrders) {
waitingListPanel.add(new JLabel(order.toString()));
}
for (Order order : myTickets) {
myTicketsPanel.add(new JLabel(order.toString()));
}
paidPanel.repaint();
waitingListPanel.repaint();
myTicketsPanel.repaint();
}
private void initTrainData() {
trainList = new ArrayList<>();
trainList.add(new Train("G123", "08:00", 150));
trainList.add(new Train("G124", "09:30", 100));
trainList.add(new Train("G125", "11:00", 200));
trainList.add(new Train("G126", "13:00", 0));
trainList.add(new Train("G127", "15:00", 75));
}
class Train {
private String trainNumber;
private String departureTime;
private int remainingSeats;
public Train(String trainNumber, String departureTime, int remainingSeats) {
this.trainNumber = trainNumber;
this.departureTime = departureTime;
this.remainingSeats = remainingSeats;
}
public String getTrainNumber() {
return trainNumber;
}
public String getDepartureTime() {
return departureTime;
}
public int getRemainingSeats() {
return remainingSeats;
}
public boolean book() {
if (remainingSeats > 0) {
remainingSeats--;
return true;
}
return false;
}
}
class Order {
private Train train;
private boolean isPaid;
public Order(Train train, boolean isPaid) {
this.train = train;
this.isPaid = isPaid;
}
@Override
public String toString() {
return isPaid ? "已支付: " + train.getTrainNumber() + " " + train.getDepartureTime() :
"候补: " + train.getTrainNumber() + " " + train.getDepartureTime();
}
}
public static void main(String[] args) {
new TrainBookingSystem();
}
}
代码注释:
// 导入Swing库,用于创建图形用户界面
import javax.swing.*;
// 导入AWT库,包含用于构建图形用户界面和图像、字体、颜色等资源的类
import java.awt.*;
// 导入AWT的事件处理库,用于处理如按钮点击等用户事件
import java.awt.event.ActionEvent;
// 导入Java的集合库,用于创建列表
import java.util.ArrayList;
import java.util.List;
// 定义一个名为TrainBookingSystem的公共类,代表火车订票系统
public class TrainBookingSystem {
// 声明多个私有成员变量,分别用于存储框架、面板、文本字段、按钮、火车列表和订单列表等
private JFrame frame;
private JPanel loginPanel, mainPanel;
private JTextField usernameField;
private JPasswordField passwordField; // 改用JPasswordField来更安全地处理密码输入
private JTextField departureField, destinationField;
private JButton searchButton;
private List<Train> trainList;
private List<Order> paidOrders;
private List<Order> waitingListOrders;
private List<Order> myTickets;
private JPanel paidPanel, waitingListPanel, myTicketsPanel;
// 构造函数,用于初始化系统
public TrainBookingSystem() {
// 创建框架并设置其标题、关闭操作和大小
frame = new JFrame("12306 Train Booking System");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
// 创建登录界面
createLoginInterface();
// 初始化火车数据
initTrainData();
// 初始化订单列表
paidOrders = new ArrayList<>();
waitingListOrders = new ArrayList<>();
myTickets = new ArrayList<>();
}
// 创建一个登录界面的方法
private void createLoginInterface() {
// 创建一个布局为BorderLayout的面板
loginPanel = new JPanel(new BorderLayout());
// 添加欢迎标签到面板的北部
loginPanel.add(createWelcomeLabel(), BorderLayout.NORTH);
// 创建一个用于账号和密码输入的面板,布局为GridBagLayout
JPanel authPanel = new JPanel(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
// 设置GridBagConstraints对象,用于指定组件在GridBagLayout中的位置和填充方式
constraints.insets = new Insets(10, 5, 10, 5);
constraints.fill = GridBagConstraints.HORIZONTAL;
// 添加账号标签和文本字段到authPanel
constraints.gridx = 0;
constraints.gridy = 0;
authPanel.add(new JLabel("账号:"), constraints);
constraints.gridx = 1;
authPanel.add(usernameField = new JTextField(30), constraints);
// 添加密码标签和密码字段到authPanel
constraints.gridx = 0;
constraints.gridy = 1;
authPanel.add(new JLabel("密码:"), constraints);
constraints.gridx = 1;
authPanel.add(passwordField = new JPasswordField(30), constraints);
// 创建一个登录按钮并为其添加点击事件监听器
JButton loginButton = new JButton("登录");
loginButton.addActionListener(e -> login());
// 将登录按钮添加到authPanel,横跨两列
constraints.gridx = 0;
constraints.gridy = 2;
constraints.gridwidth = 2;
authPanel.add(loginButton, constraints);
// 将authPanel添加到loginPanel的中心区域
loginPanel.add(authPanel, BorderLayout.CENTER);
// 将loginPanel设置为框架的内容面板,并设置框架的位置和可见性
frame.setContentPane(loginPanel);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// 创建一个欢迎标签的方法
private JLabel createWelcomeLabel() {
// 创建一个标签并设置其文本、字体和对齐方式
JLabel welcomeLabel = new JLabel("欢迎使用12306订票系统");
Font font = new Font("SansSerif", Font.BOLD, 24);
welcomeLabel.setFont(font);
welcomeLabel.setHorizontalAlignment(SwingConstants.CENTER);
// 返回创建的欢迎标签
return welcomeLabel;
}
// 定义一个登录方法
private void login() {
// 从文本字段中获取账号和密码
String username = usernameField.getText();
char[] passwordChars = passwordField.getPassword();
String password = new String(passwordChars);
// 如果账号和密码都不为空,则执行登录逻辑
if (!username.isEmpty() && !password.isEmpty()) {
// 假设的登录逻辑(实际中应包含与数据库的交互)
// 将框架的内容面板更改为主界面,并重新验证和重绘框架
frame.setContentPane(createMainInterface());
frame.revalidate();
frame.repaint();
} else {
// 如果账号或密码为空,则显示错误消息
JOptionPane.showMessageDialog(frame, "请输入账号和密码!");
}
}
// 创建一个主界面的方法
private JPanel createMainInterface() {
// 创建一个布局为BorderLayout的主面板
mainPanel = new JPanel(new BorderLayout());
// 创建左侧的面板用于输入始发站和终点站
JPanel leftPanel = new JPanel(new BorderLayout());
leftPanel.setPreferredSize(new Dimension((int)(frame.getWidth() * 0.75), frame.getHeight()));
leftPanel.setBorder(BorderFactory.createTitledBorder("车票查询"));
// 创建一个用于输入始发站和终点站的面板,布局为GridBagLayout
JPanel inputPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
// 设置GridBagConstraints对象
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(10, 5, 10, 5);
// 添加始发站标签和文本字段到inputPanel
gbc.gridx = 0;
gbc.gridy = 0;
inputPanel.add(new JLabel("始发站:"), gbc);
gbc.gridx = 1;
gbc.gridwidth = 2;
inputPanel.add(departureField = new JTextField(30), gbc);
// 添加终点站标签和文本字段到inputPanel
gbc.gridx = 0;
gbc.gridy = 1;
inputPanel.add(new JLabel("终点站:"), gbc);
gbc.gridx = 1;
inputPanel.add(destinationField = new JTextField(30), gbc);
// 创建一个查询按钮并为其添加点击事件监听器
searchButton = new JButton("车次查询");
searchButton.addActionListener(e -> showTrainList());
// 将查询按钮添加到inputPanel,横跨三列
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 3;
inputPanel.add(searchButton, gbc);
// 将inputPanel添加到leftPanel的中心区域
leftPanel.add(inputPanel, BorderLayout.CENTER);
// 创建右侧的面板用于显示个人订单
JPanel rightPanel = new JPanel(new GridLayout(3, 1)); // 3行1列的网格布局
rightPanel.setPreferredSize(new Dimension(frame.getWidth() / 4, frame.getHeight()));
rightPanel.setBorder(BorderFactory.createTitledBorder("个人订单查询"));
// 初始化并添加用于显示已支付订单、候补订单和本人车票的面板
paidPanel = new JPanel(new FlowLayout());
waitingListPanel = new JPanel(new FlowLayout());
myTicketsPanel = new JPanel(new FlowLayout());
// 创建订单管理按钮并为其添加点击事件监听器
JButton paidOrdersButton = new JButton("已支付");
paidOrdersButton.addActionListener(e -> showOrders(paidOrders));
rightPanel.add(paidOrdersButton, BorderLayout.NORTH); // 注意:这里应该是使用GridLayout,而不是BorderLayout
// 创建候补订单按钮并为其添加点击事件监听器
JButton waitingListOrdersButton = new JButton("候补订单");
waitingListOrdersButton.addActionListener(e -> showOrders(waitingListOrders));
rightPanel.add(waitingListOrdersButton, 1); // 在GridLayout中,
// 这里的索引参数在GridLayout中应该是一个数字,表示添加到第几行(从0开始)。
// 但是,因为GridLayout并没有直接提供索引来指定具体位置,
// 所以我们简单地按照顺序添加。在GridLayout中,组件会自动按行和列的布局进行排列。
rightPanel.add(waitingListOrdersButton); // 正确地添加候补订单按钮到rightPanel
// 创建本人车票按钮并为其添加点击事件监听器
JButton myTicketsButton = new JButton("本人车票");
myTicketsButton.addActionListener(e -> showOrders(myTickets));
rightPanel.add(myTicketsButton); // 将本人车票按钮添加到rightPanel
// 注意:这里添加了一个JLabel(" ")作为占位符是不必要的,因为GridLayout会自动处理布局
// rightPanel.add(new JLabel(" "), BorderLayout.CENTER); // 移除这个不必要的代码
// 将leftPanel和rightPanel添加到mainPanel中
mainPanel.add(leftPanel, BorderLayout.CENTER);
mainPanel.add(rightPanel, BorderLayout.EAST);
// 初始化并更新订单显示
updateOrderDisplays();
// 返回创建的主界面面板
return mainPanel;
}
// 显示订单列表的方法
private void showOrders(List<Order> orders) {
if (orders.isEmpty()) {
// 如果没有订单,则显示一个消息框提示没有订单
JOptionPane.showMessageDialog(frame, "当前没有订单!");
} else {
// 如果有订单,则创建一个消息框显示所有订单信息
String message = "订单信息:\n";
for (Order order : orders) {
message += order.toString() + "\n";
}
JOptionPane.showMessageDialog(frame, message, "订单列表", JOptionPane.INFORMATION_MESSAGE);
}
}
// 显示车次列表的方法
private void showTrainList() {
// 创建一个对话框用于显示车次列表
JDialog dialog = new JDialog(frame, "车次列表", true);
dialog.setLayout(new BorderLayout());
dialog.setSize(400, 300);
// 创建一个面板用于显示火车信息,布局为GridLayout,大小与trainList的大小一致
JPanel trainInfoPanel = new JPanel(new GridLayout(trainList.size(), 1));
// 遍历trainList中的每一辆火车
for (Train train : trainList) {
// 为每一辆火车创建一个面板
JPanel trainPanel = new JPanel(new BorderLayout());
// 创建订票和候补按钮
JButton bookButton = new JButton("订票");
JButton waitlistButton = new JButton("候补");
waitlistButton.setVisible(false); // 默认情况下不显示候补按钮
// 为订票按钮添加点击事件监听器
bookButton.addActionListener(evt -> {
if (train.book()) {
// 如果订票成功,则添加订单并显示成功消息
addOrder(train, true);
JOptionPane.showMessageDialog(frame, "订票成功!");
dialog.dispose(); // 关闭车次列表对话框
} else {
// 如果订票失败(没有剩余座位),则显示候补按钮
waitlistButton.setVisible(true);
}
});
// 为候补按钮添加点击事件监听器
waitlistButton.addActionListener(evt -> {
// 添加候补订单并显示成功消息
addOrder(train, false);
JOptionPane.showMessageDialog(frame, "候补成功!");
dialog.dispose(); // 关闭车次列表对话框
});
// 在trainPanel中添加火车信息和按钮
trainPanel.add(new JLabel(train.getTrainNumber() + " - " + train.getDepartureTime() + " - 剩余票数:" + train.getRemainingSeats()), BorderLayout.CENTER);
JPanel buttonPanel = new JPanel(new FlowLayout());
buttonPanel.add(bookButton);
buttonPanel.add(waitlistButton);
trainPanel.add(buttonPanel, BorderLayout.EAST);
// 将trainPanel添加到trainInfoPanel中
trainInfoPanel.add(trainPanel);
}
// 创建一个滚动面板来包含trainInfoPanel,并添加到对话框中
JScrollPane scrollPane = new JScrollPane(trainInfoPanel);
dialog.add(scrollPane, BorderLayout.CENTER); // 将滚动面板添加到对话框的中心位置
// 设置对话框的位置相对于父窗口居中
dialog.setLocationRelativeTo(frame);
// 设置对话框为可见
dialog.setVisible(true);
}
// 添加订单到对应列表的方法
private void addOrder(Train train, boolean isPaid) {
Order order = new Order(train, isPaid); // 创建一个新的订单对象
// 根据订单是否已支付,将其添加到对应的列表中
if (isPaid) {
paidOrders.add(order); // 添加到已支付订单列表
myTickets.add(order); // 添加到本人车票列表
} else {
waitingListOrders.add(order); // 添加到候补订单列表
}
// 更新订单显示面板的内容
updateOrderDisplays();
}
// 更新订单显示面板的方法
private void updateOrderDisplays() {
// 清除之前的订单信息
paidPanel.removeAll();
waitingListPanel.removeAll();
myTicketsPanel.removeAll();
// 遍历订单列表,将订单信息添加到对应的面板中
for (Order order : paidOrders) {
paidPanel.add(new JLabel(order.toString()));
}
for (Order order : waitingListOrders) {
waitingListPanel.add(new JLabel(order.toString()));
}
for (Order order : myTickets) {
myTicketsPanel.add(new JLabel(order.toString()));
}
// 重新绘制面板以显示新的订单信息
paidPanel.repaint();
waitingListPanel.repaint();
myTicketsPanel.repaint();
}
// 初始化火车数据的方法
private void initTrainData() {
trainList = new ArrayList<>();
// 添加几辆火车到trainList中,包括车次、发车时间和剩余座位数
trainList.add(new Train("G123", "08:00", 150));
trainList.add(new Train("G124", "09:30", 100));
trainList.add(new Train("G125", "11:00", 200));
trainList.add(new Train("G126", "13:00", 0)); // 这辆火车没有剩余座位
trainList.add(new Train("G127", "15:00", 75));
}
// 火车类Train,表示一辆火车
class Train {
// ...(类的成员变量和方法省略,已在前面定义)
// book方法,尝试预订火车票
public boolean book() {
if (remainingSeats > 0) { // 如果剩余座位数大于0
remainingSeats--; // 预订成功后,剩余座位数减1
return true; // 返回true表示预订成功
}
return false; // 返回false表示预订失败(没有剩余座位)
}
}
// 订单类Order,表示一个订单
class Order {
// ...(类的成员变量和方法省略,已在前面定义)
// toString方法,返回订单的字符串表示形式
@Override
public String toString() {
return isPaid ? "已支付: " + train.getTrainNumber() + " " + train.getDepartureTime() :
"候补: " + train.getTrainNumber() + " " + train.getDepartureTime();
}
}
// 主方法,程序入口
public static void main(String[] args) {
new TrainBookingSystem(); // 创建TrainBookingSystem对象,启动订票系统
}
}