You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java学生追踪器:为Add按钮添加点击计数器以指定文件写入行号

学生追踪器项目:计数器与文件写入问题解决

问题描述

我是Java新手,正在完成学校项目——学生追踪器,目前在搭建界面布局,实现将学生信息写入文件的功能。需要在每次点击Add按钮时增加一个计数器,以此确定文件的写入行号。但遇到了问题:

  • 定义普通变量用a++实现计数时,因为匿名内部类的限制,无法持续累加;
  • 若在内部类中初始化变量,每次点击按钮时变量都会被重置。

原代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException {
        File StudentNames = new File("StudentNames.txt");
        File StudentGrades = new File("StudentGrades.txt");
        File StudentScore = new File("StudentScore.txt");

        FileWriter NameFileWriter = new FileWriter("StudentNames.txt");
        FileWriter GradeFileWriter = new FileWriter("StudentGrades.txt");
        FileWriter ScoreFileWriter = new FileWriter("StudentScore.txt");

        FileReader NameFileReader = new FileReader(StudentNames);
        FileReader GradeFileReader = new FileReader(StudentGrades);
        FileReader ScoreFileReader = new FileReader(StudentScore);

        String[] NamesString = new String[] {""};
        List<String> NamesList = Arrays.asList(NamesString);

        JFrame frame = new JFrame("Tyke Tracking");
        frame.setSize(500, 500);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Adding a panel to center the buttons
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints Center = new GridBagConstraints();

        Center.gridx = 0;
        JButton StudentsButton = new JButton("Students");
        panel.add(StudentsButton, Center);

        Center.gridx = 1;
        JButton PrizesButton = new JButton("Prizes");
        panel.add(PrizesButton, Center);

        frame.getContentPane().add(panel);
        frame.setVisible(true);

        //Student Section
        JFrame StuFrame = new JFrame("Tyke Tracking Students");
        StuFrame.setSize(500,500);
        StuFrame.setResizable(false);
        StuFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel StuPanelLeft = new JPanel();

        JTextArea StudentsListed = new JTextArea();
        StudentsListed.setEditable(false);
        StudentsListed.setPreferredSize((new Dimension(250,500)));
        StuPanelLeft.add(StudentsListed);

        JPanel StuPanelRight = new JPanel(new GridBagLayout());
        GridBagConstraints StuRight = new GridBagConstraints();

        StuRight.gridy = 0;
        JButton AddStu = new JButton("Add Students");
        StuPanelRight.add(AddStu, StuRight);

        StuRight.gridy = 1;
        JButton EditStu = new JButton("Edit Students");
        StuPanelRight.add(EditStu, StuRight);

        StuRight.gridy = 2;
        JButton Report = new JButton("Get Report");
        Report.setPreferredSize(new Dimension(130,23)); //Making it even to other buttons
        StuPanelRight.add(Report, StuRight);

        StuRight.gridy = 3;
        JButton backButton = new JButton("Back");
        backButton.setPreferredSize(new Dimension(130,23));
        StuPanelRight.add(backButton, StuRight);

        StuFrame.getContentPane().add(StuPanelLeft, BorderLayout.WEST);
        StuFrame.getContentPane().add(StuPanelRight);

        //Adding Students
        JFrame Adding = new JFrame("Adding Students");
        Adding.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        Adding.setSize(200,150);
        Adding.setResizable(false);

        JPanel AddStuPanel = new JPanel(new GridBagLayout());
        JPanel AddStuPanelTop = new JPanel(new GridBagLayout());
        GridBagConstraints AddStuGBC = new GridBagConstraints();

        AddStuGBC.gridy = 1;
        AddStuGBC.fill = GridBagConstraints.HORIZONTAL;
        JTextField addNameField = new JTextField();
        addNameField.setPreferredSize(new Dimension(150,20));
        AddStuPanelTop.add(addNameField, AddStuGBC);

        AddStuGBC.gridy = 0;
        JLabel nameLabel = new JLabel("Name:");
        AddStuPanelTop.add(nameLabel, AddStuGBC);

        AddStuGBC.gridy = 2;
        JLabel gradeLabel = new JLabel("Grade %:");
        AddStuPanelTop.add(gradeLabel, AddStuGBC);

        AddStuGBC.gridy = 3;
        JTextField addGradeField = new JTextField();
        addGradeField.setPreferredSize(new Dimension(150,20));
        AddStuPanelTop.add(addGradeField, AddStuGBC);

        AddStuGBC.gridy = 4;
        JButton addButton = new JButton("Add");
        AddStuPanel.add(addButton, AddStuGBC);

        AddStuGBC.gridx = 1;
        JButton closeButton = new JButton("Close");
        AddStuPanel.add(closeButton, AddStuGBC);

        Adding.getContentPane().add(AddStuPanelTop, BorderLayout.CENTER);
        Adding.getContentPane().add(AddStuPanel, BorderLayout.SOUTH);
        Adding.setVisible(false);

        addButton.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    NameFileWriter.append(addNameField.getText());
                    NameFileWriter.close();}
                catch (IOException ignored) {}
                try {
                    GradeFileWriter.append(addGradeField.getText());
                    GradeFileWriter.close();}
                catch (IOException ignored) {}
                //Way to count how many students there are, to write to correct line in files
                }
        });

        closeButton.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                Adding.setVisible(false);
            }
        });

        StudentsButton.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.setVisible(false);
                StuFrame.setVisible(true);
            }
        });

        backButton.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                StuFrame.setVisible(false);
                frame.setVisible(true);
            }
        });

        AddStu.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                Adding.setVisible(true);
            }
        });


    }
}

解决方案

1. 解决计数器累加问题

Java的匿名内部类只能访问final或实际不可变的外部变量,普通int变量无法直接修改。可以用两种方式实现持久计数:

方式一:使用静态变量

在Main类中定义静态计数器变量,它属于类本身,不会被重置:

public class Main {
    // 定义静态计数器,初始值为0
    private static int studentCount = 0;

    public static void main(String[] args) throws IOException {
        // ... 原代码 ...

在addButton的事件监听中直接累加:

addButton.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        // 每次点击累加计数器
        Main.studentCount++;
        
        // ... 文件写入逻辑 ...
    }
});

方式二:使用AtomicInteger

如果需要线程安全(Swing事件线程是单线程,非必须但写法规范),可以用java.util.concurrent.atomic.AtomicInteger:

// 在main方法中导入并声明
import java.util.concurrent.atomic.AtomicInteger;
// ...
AtomicInteger studentCount = new AtomicInteger(0);

在事件监听中调用递增方法:

addButton.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        // 累加并获取最新值
        int currentCount = studentCount.incrementAndGet();
        
        // ... 文件写入逻辑 ...
    }
});

2. 修复文件写入的潜在问题

原代码中每次写入后就关闭FileWriter,第二次点击会因流已关闭抛出异常,且未用追加模式会覆盖原有文件。建议用try-with-resources语法自动管理流,同时指定追加模式:

addButton.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        Main.studentCount++;
        
        // 写入姓名,追加模式,自动关闭流
        try (FileWriter nameWriter = new FileWriter("StudentNames.txt", true)) {
            nameWriter.append(addNameField.getText()).append("\n"); // 加换行符,每行一个学生
        } catch (IOException ex) {
            ex.printStackTrace(); // 不要忽略异常,方便排错
        }
        
        // 写入成绩
        try (FileWriter gradeWriter = new FileWriter("StudentGrades.txt", true)) {
            gradeWriter.append(addGradeField.getText()).append("\n");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        // 清空输入框,提升用户体验
        addNameField.setText("");
        addGradeField.setText("");
    }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 22:55:27