diff --git a/src/view/ExamView.java b/src/view/ExamView.java new file mode 100644 index 0000000..3789205 --- /dev/null +++ b/src/view/ExamView.java @@ -0,0 +1,140 @@ +package view; + +import model.Question; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; +import java.awt.*; +import java.util.List; + + +public class ExamView extends JPanel { + private final JLabel progressLabel = new JLabel(" ", SwingConstants.CENTER); + private final JProgressBar progressBar = new JProgressBar(); + private final JTextPane questionPane = new JTextPane(); + private final JRadioButton[] optionButtons = new JRadioButton[4]; + private final ButtonGroup optionsGroup = new ButtonGroup(); + + private final JButton prevButton = new JButton("上一题"); + private final JButton nextButton = new JButton("下一题"); + private final JButton finishButton = new JButton("交卷并评分"); + + public ExamView() { + setLayout(new BorderLayout(20, 20)); + setBorder(new EmptyBorder(20, 40, 40, 40)); + + // --- 顶部进度区域 --- + JPanel topPanel = new JPanel(new BorderLayout(0, 10)); + progressLabel.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 20)); + topPanel.add(progressLabel, BorderLayout.NORTH); + + progressBar.setPreferredSize(new Dimension(1, 15)); + topPanel.add(progressBar, BorderLayout.CENTER); + add(topPanel, BorderLayout.NORTH); + + // --- 中间题目区域 --- + questionPane.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 36)); + questionPane.setEditable(false); + questionPane.setFocusable(false); + questionPane.setOpaque(false); + StyledDocument doc = questionPane.getStyledDocument(); + SimpleAttributeSet center = new SimpleAttributeSet(); + StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); + doc.setParagraphAttributes(0, doc.getLength(), center, false); + + JPanel questionWrapper = new JPanel(new BorderLayout()); + questionWrapper.setOpaque(false); + questionWrapper.add(questionPane, BorderLayout.CENTER); + add(questionWrapper, BorderLayout.CENTER); + + // --- 底部选项和导航 --- + JPanel southPanel = new JPanel(new BorderLayout(20, 30)); + + // --- 选项面板 --- + JPanel optionsPanel = new JPanel(new GridBagLayout()); + optionsPanel.setOpaque(false); + GridBagConstraints gbcOpt = new GridBagConstraints(); + gbcOpt.insets = new Insets(15, 80, 15, 80); // 调整选项的内外边距 + gbcOpt.anchor = GridBagConstraints.WEST; + + for (int i = 0; i < 4; i++) { + optionButtons[i] = new JRadioButton(); + optionButtons[i].setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20)); + optionButtons[i].setOpaque(false); + optionsGroup.add(optionButtons[i]); + } + + + gbcOpt.gridx = 0; gbcOpt.gridy = 0; optionsPanel.add(optionButtons[0], gbcOpt); // 位置 A + gbcOpt.gridx = 1; gbcOpt.gridy = 0; optionsPanel.add(optionButtons[1], gbcOpt); // 位置 B + gbcOpt.gridx = 0; gbcOpt.gridy = 1; optionsPanel.add(optionButtons[2], gbcOpt); // 位置 C + gbcOpt.gridx = 1; gbcOpt.gridy = 1; optionsPanel.add(optionButtons[3], gbcOpt); // 位置 D + + JPanel optionsWrapper = new JPanel(new GridBagLayout()); + optionsWrapper.setOpaque(false); + optionsWrapper.add(optionsPanel); + southPanel.add(optionsWrapper, BorderLayout.CENTER); + + // --- 导航按钮面板 --- + JPanel navigationPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 0)); + prevButton.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16)); + nextButton.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16)); + finishButton.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 16)); + finishButton.putClientProperty("JButton.buttonType", "roundRect"); + + navigationPanel.add(prevButton); + navigationPanel.add(finishButton); + navigationPanel.add(nextButton); + southPanel.add(navigationPanel, BorderLayout.SOUTH); + + add(southPanel, BorderLayout.SOUTH); + } + + public void displayQuestion(Question q, int qNum, int total, int savedAnswerIndex) { + progressLabel.setText(String.format("第 %d 题 / 共 %d 题", qNum, total)); + progressBar.setValue(qNum); + questionPane.setText(q.getQuestionText()); + + StyledDocument doc = questionPane.getStyledDocument(); + SimpleAttributeSet center = new SimpleAttributeSet(); + StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); + doc.setParagraphAttributes(0, doc.getLength(), center, false); + + optionsGroup.clearSelection(); + List options = q.getOptions(); + + char optionLabel = 'A'; + for (int i = 0; i < 4; i++) { + optionButtons[i].setText(optionLabel + ". " + options.get(i)); + optionLabel++; + } + + if (savedAnswerIndex != -1) { + optionButtons[savedAnswerIndex].setSelected(true); + } + } + + public void setupForExam(int totalQuestions) { + progressBar.setMinimum(1); + progressBar.setMaximum(totalQuestions); + } + + public void updateNavigationButtons(int qIndex, int total) { + prevButton.setEnabled(qIndex > 0); + nextButton.setEnabled(qIndex < total - 1); + nextButton.setText(qIndex == total - 2 ? "最后一题" : "下一题"); + } + + public int getSelectedIndex() { + for (int i = 0; i < 4; i++) { + if (optionButtons[i].isSelected()) { return i; } + } + return -1; + } + + public JButton getPrevButton() { return prevButton; } + public JButton getNextButton() { return nextButton; } + public JButton getFinishButton() { return finishButton; } +} \ No newline at end of file