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

Java Swing Quiz游戏切换面板时如何确保共享String变量已赋值?

问题排查:PracticePanel读取SharedData路径为null的问题

问题根源

你的代码里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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:39:53