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
相关产品推荐
相关产品推荐

