Java Swing Quiz游戏切换面板时如何确保共享String变量已赋值?
问题根源
你的代码里MainFrame初始化时就提前创建了PracticePanel,此时用户还没选择科目,SharedData的subject字段还是null。而CardLayout的show方法只是显示/隐藏已存在的面板,不会重新调用面板的构造函数。所以后续用户选完科目切换到PracticePanel时,面板里的QnA早已经用null路径初始化了,自然报错。
解决方案
有两种可行的修复方式,选其一即可:
方案1:延迟创建PracticePanel
只在用户点击Practice按钮时才创建并添加PracticePanel到CardLayout,确保此时SharedData已经有了正确的路径。
修改MainFrame:
import javax.swing.*; import java.awt.*; class MainFrame extends JFrame { private CardLayout cardLayout; private JPanel mainPanel; private SharedData sharedData; public MainFrame() { setTitle("QUIZ"); setSize(1000, 750); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); sharedData = new SharedData(); cardLayout = new CardLayout(); mainPanel = new JPanel(cardLayout); // 只初始化前两个面板 mainPanel.add(new SubjectsPanel(this, sharedData), "SubjectsPanel"); mainPanel.add(new ModePanel(this, sharedData), "ModePanel"); add(mainPanel); cardLayout.show(mainPanel, "SubjectsPanel"); setVisible(true); // 建议把setVisible放在最后,避免组件初始化问题 } public void switchToPanel(String panelName) { // 切换到PracticePanel时检查是否已存在,不存在则创建 if ("PracticePanel".equals(panelName) && mainPanel.getComponentCount() < 3) { mainPanel.add(new PracticePanel(this, sharedData), "PracticePanel"); } cardLayout.show(mainPanel, panelName); } }
方案2:修改PracticePanel,延迟初始化QnA
把QnA的初始化逻辑从构造函数移到单独的方法,切换到PracticePanel时调用该方法读取最新路径。
修改PracticePanel:
import java.awt.event.*; import java.awt.*; import javax.swing.*; public class PracticePanel extends JPanel { JLabel question; JCheckBox c[] = new JCheckBox[4]; JButton b1, b2; int q_curent = 0, n = 3; QnA q; private SharedData sharedData; private MainFrame frame; PracticePanel(MainFrame frame, SharedData sharedData) { this.frame = frame; this.sharedData = sharedData; setLayout(new GridLayout(7, 0)); question = new JLabel(); question.setFont(new Font("Arial", Font.BOLD, 20)); add(question); for (int i = 0; i < 3; i++) { c[i] = new JCheckBox(); add(c[i]); } b1 = new JButton("Next"); b2 = new JButton("Previous"); b1.setFont(new Font("Arial", Font.BOLD, 18)); b2.setFont(new Font("Arial", Font.BOLD, 18)); b2.setEnabled(false); add(b1); add(b2); // 按钮事件逻辑保留 b1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { q_curent++; b2.setEnabled(true); set(); } }); b2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { q_curent--; b1.setText("Next"); b1.setEnabled(true); set(); if (q_curent == 0) { b2.setEnabled(false); } } }); } // 添加初始化QnA的方法 public void initQnA() { String subjectPath = sharedData.getSubjectChosen(); if (subjectPath == null) { JOptionPane.showMessageDialog(this, "请先选择科目!"); frame.switchToPanel("SubjectsPanel"); return; } this.q = new QnA(subjectPath); q_curent = 0; b2.setEnabled(false); set(); } private void set() { if (q == null) return; question.setText(q.questions[q_curent]); for (int j = 0; j < 3; j++) { c[j].setText(q.options[q_curent][j]); } } }
然后修改MainFrame的switchToPanel方法,切换到PracticePanel时调用initQnA:
public void switchToPanel(String panelName) { cardLayout.show(mainPanel, panelName); if ("PracticePanel".equals(panelName)) { ((PracticePanel)mainPanel.getComponent(2)).initQnA(); } }
额外优化建议
- 把
setVisible(true)放在MainFrame构造函数的最后,避免组件还没完全初始化就显示导致的问题。 - SharedData里的
subject字段建议设为private,只通过get/set方法访问,符合封装原则。 - QnA类里可以添加空值判断,避免传入null时直接报错:
public QnA(String subject) { if (subject == null || subject.isEmpty()) { System.out.println("无效的文件路径"); questions = new String[0]; options = new String[0][0]; return; } // 原有的文件读取逻辑 }
内容的提问来源于stack exchange,提问作者lorau
相关产品推荐
相关产品推荐

