You need to enable JavaScript to run this app. Java Swing 实现ATM控制台输出重定向与GUI按钮输入
优惠活动
大模型
产品
解决方案
定价
更多

Java Swing 实现ATM控制台输出重定向与GUI按钮输入

Swing版ATM交互程序改造实现方案

核心改造逻辑

  • 完整保留现有AtmProgram类的所有业务规则,不改动核心存款、取款、余额计算逻辑
  • 把原本打印到控制台的输出流,重定向到界面上的JTextArea文本域,完全替代控制台展示效果
  • 移除所有Scanner键盘输入逻辑,通过界面上的数字、确认、清除按钮维护输入缓存,完全替代物理键盘交互

具体实现步骤

1. 实现控制台输出重定向到文本域

注意:所有对Swing组件的操作必须放到事件 dispatch 线程中执行,否则会出现UI卡死、组件渲染异常的问题。自定义输出流中一定要用SwingUtilities.invokeLater切换线程。

// 自定义输出流,承接原本所有控制台输出
private OutputStream guiOutputStream = new OutputStream() {
    @Override
    public void write(int b) {
        char currentChar = (char) b;
        // 切换到Swing UI线程更新文本域,避免线程安全问题
        SwingUtilities.invokeLater(() -> {
            textArea.append(String.valueOf(currentChar));
            // 自动滚动到文本末尾,展示最新输出
            textArea.setCaretPosition(textArea.getDocument().getLength());
        });
    }
};

界面初始化时,替换系统默认的标准输出、错误流:

PrintStream guiPrintStream = new PrintStream(guiOutputStream, true);
System.setOut(guiPrintStream);  // 替换System.out的输出目标
System.setErr(guiPrintStream);   // 替换System.err的输出目标

完成这一步后,原来代码里所有的System.out.println、System.out.printf都会自动展示到文本域,不需要逐行修改原来的打印逻辑。

2. 实现按钮交互的输入缓存

用一个全局的字符串缓存,替代Scanner的标准输入源:

// 存储用户通过按钮输入的内容
private StringBuilder inputBuffer = new StringBuilder();
// 记录当前流程是否在等待用户提交输入
private boolean waitingForInput = false;
// 存储用户已提交的输入值,供主流程读取
private String submittedInput = "";

给所有按钮绑定对应的事件逻辑:

  • 数字按钮(0-9):点击时将对应数字追加到输入缓存,同时和控制台输入一样,把字符直接展示在文本域上
    // 以数字1按钮为例,所有数字按钮逻辑完全一致
    btn1.addActionListener(e -> {
        if (!waitingForInput) return; // 只有流程等待输入时才允许输入
        inputBuffer.append("1");
        textArea.append("1");
    });
    
  • 清除按钮:清空当前输入缓存,删除文本域上当前正在输入的内容,模拟退格/清除效果
    correctionButton.addActionListener(e -> {
        inputBuffer.setLength(0);
        // 删除当前输入行的内容
        int caretPos = textArea.getCaretPosition();
        int lineStart = textArea.getLineStartOffset(textArea.getLineOfOffset(caretPos));
        textArea.replaceRange("", lineStart, caretPos);
    });
    
  • 确认按钮:将输入缓存的内容作为提交值,唤醒主流程的输入等待
    entrerButton.addActionListener(e -> {
        if (!waitingForInput) return;
        submittedInput = inputBuffer.toString().trim();
        inputBuffer.setLength(0);
        textArea.append("\n"); // 模拟按回车的换行效果
        waitingForInput = false; // 标记输入已提交
    });
    
  • 退出按钮:直接触发程序退出逻辑,和原代码菜单选择“4.退出”的逻辑完全一致
    quitterButton.addActionListener(e -> System.exit(0));
    

3. 重构主流程逻辑,适配GUI输入

原Main类中的ATM主循环不能直接在Swing事件线程中运行(会导致UI卡死),需要放到独立的后台线程执行,同时把原来从Scanner读输入的地方,替换为从我们的按钮输入缓存读取:

// 后台线程执行ATM主流程,不阻塞UI响应
new Thread(() -> {
    AtmProgram account = new AtmProgram();
    while (true) {
        // 打印菜单的逻辑完全和原代码一致,因为输出已经重定向到文本域
        System.out.println("************************************************");
        System.out.println("1.Solde");
        System.out.println("2.Dépôt");
        System.out.println("3.Retrait");
        System.out.println("4.Quitter");
        System.out.println("************************************************");
        System.out.print("Entrer Menu Option(et press Entrer):");

        // 替代原来input.nextInt()的逻辑
        int menuOption = readIntInput();

        // 原代码中的switch分支逻辑完全复用,不需要修改
        switch (menuOption) {
            // ... 所有case逻辑和原代码完全一致
        }
    }
}).start();

其中用于替代Scanner读输入的通用方法如下:

// 阻塞等待用户输入整数,直到拿到合法整数值
private int readIntInput() {
    while (true) {
        waitingForInput = true;
        // 等待用户提交输入
        while (waitingForInput) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return -1;
            }
        }
        try {
            return Integer.parseInt(submittedInput);
        } catch (NumberFormatException e) {
            System.out.println("Option de Menu non valide");
        }
    }
}

// 阻塞等待用户输入浮点数,用于存款、取款的金额输入
private double readDoubleInput() {
    while (true) {
        waitingForInput = true;
        while (waitingForInput) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return -1;
            }
        }
        try {
            return Double.parseDouble(submittedInput);
        } catch (NumberFormatException e) {
            System.out.println("Entrée non valide, veuillez entrer un nombre");
        }
    }
}

4. 细节适配说明

  • AtmProgram类不需要任何修改,类里所有的输出、异常抛出逻辑都会通过重定向的流自动展示到文本域
  • 如果需要支持输入带小数的金额,可以在界面上补充小数点按钮,绑定逻辑和数字按钮完全一致
  • 原代码中退出时需要确认“O/N”的逻辑,可以直接复用字符串读入方法(和整数、浮点数读入逻辑一致),等待用户点击对应按钮提交即可

内容的提问来源于stack exchange,提问作者ettalha0x

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 17:36:04