Java程序设计:必实验5 GUI高级应用

题目:

编写Java应用程序,实现“Java机考”的功能(“单机版Java简易机考程序”),包含单选题、多选题和判断题三种题型。

在主线程中创建一个Frame类型的窗口,在该窗口中再创建一个线程giveQuestion。

线程giveQuestion每隔20秒钟输出一个选择题(含A,B,C,D共4个选项,要求支持单选题和多选题,单选题用radio button,多选题用check box)或一个判断题(用radio button),选择题和判断题混合着给出;用户输入答案并按提交按钮提交结果(达到20秒自动提交结果);程序判断用户输入的答案是否正确(如果错选或漏选均得零分),并实时显示当前题目的正确答案、已经给出的题目的数量(分别给出单选题数量、多选题数量和判断题数量)、用户答对的数量(分别给出单选题数量、多选题数量和判断题数量)、用户的成绩和用户答题所花的总的时间。

如此循环15次,包括随机选择的5个单选题(每题1分)、随机选择的5个多选题(每题2分)和随机选择的5个判断题(每题1分),结束测试时给出最终成绩。

题库应至少包含10个单选题、10个多选题和10个判断题。要求使用图形用户界面。

思路:

定义Question一个简单的题目类,以及单选题子类、多选题子类和判断对错题子类:

(1)Question(问题类):抽象类,表示一个通用的问题,包含问题描述。

包含一个抽象方法 getCorrectAnswer,该方法要求具体子类提供正确的答案。

(2)SingleChoiceQuestion(单选题类):继承自问题类,表示单选题。

包含一个选择列表和一个正确答案。

(3)MultipleChoiceQuestion(多选题类):继承自问题类,表示多选题。

包含一个选择列表和多个正确答案。

(4)TrueFalseQuestion(判断对错题类):继承自问题类,表示判断对错题。

包含一个布尔值表示正确或错误。

  • 定义ExamModel 类,作为“JAVA机考”的功能:
  • 继承自 JFrame 类,表示考试模型的主窗口。首先声明了一系列常量,如总题数、不同题型的分数、问题时间间隔等。

(2)声明相关变量,包括单选、多选、判断对错的正确数,总得分以及总时间,以及定义JLabel 对象用于显示问题的描述文本,定义ButtonGroup 对象用于将单选按钮或复选框组合在一起,定义JButton 对象用于用户提交答案,定义JPanel 对象用于容纳用户选择答案的组件,例如单选按钮或复选框。

  • 初始化ExamModel ,包括准备问题库、设置用户界面和开始考试。
  • 准备好单选题10道题库,多选题10道题库,判断对错10道题库。(以下代码举前五道题的添加代码为例)
  • 初始化题库initializeQuestionBank,包括单选、多选和判断对错题。从单选、多选和判断对错题各随机选取5道,载入题库后再打乱顺序,保证随机乱序。

【1】定义通用方法getRandomQuestions,用于从给定的题目数组中随机选择指定数量的题目。首先创建一个空列表,用于存储随机选择的题目。然后创建一个副本。这个副本将用于随机选择题目。

【2】初始化题库,从单选、多选和判断对错题各随机选取5道,再使用java.util.Collections.shuffle(questionBank);打乱顺序。

(5)初始化用户界面initializeUI,先设置窗口相关属性,再定义包含一个显示问题的标签、一个用于提交答案的按钮,以及一个用于显示答案选项的面板。提交按钮的点击事件被监听,点击后将评估用户的答案并显示下一个问题。

【1】设置窗口属性:设置窗口标题,设置窗口的初始大小,设置窗口关闭时默认的操作为终止程序,将窗口定位在屏幕中央。

【2】初始化界面组件:创建一个空的标签用于显示问题;创建一个按钮组,用于管理单选按钮或单选框; "提交" 的按钮并为提交按钮添加事件监听器。

【3】设置布局管理器和添加组件:设置窗口的布局管理器为边界布局;将问题标签添加到窗口的中央位置;将提交按钮添加到窗口的下侧位置;创建一个面板用于放置答案选项,初始时为空;将答案面板添加到窗口的右侧位置。

(6)定义displayQuestion方法,用于在用户界面上显示问题和答案选项。

【1】使用setText设置问题文本和使用clearSelection清除选择和removeAll移除组件。

【2】根据问题类型添加答案选项组件。由于ButtonGroup 会确保一组单选按钮只有一个按钮被选中,因此不适用于多选题。对于多选题,直接将复选框添加到面板中。这样,就可以选择多个选项。

【3】启用提交按钮并刷新界面:启用提交按钮;重新验证界面,确保新的组件布局得到应用;重绘界面,使新的组件可见。

  • getSelectedCheckboxes()和getSelectedRadioButton()是获取用户选择的答案的方法:

通过遍历按钮组中的所有按钮,找到被用户选中的按钮,并分别返回单选按钮或复选框的文本内容。如果没有找到选中的按钮,返回相应的默认值。

【1】getSelectedRadioButton 方法:获取用户选择按钮的答案的方法。

【2】getSelectedCheckboxes 方法:获取用户选择复选框的答案的方法。

(8)evaluateAnswer根据用户选择的答案和当前问题的正确答案,更新单选、多选、判断对错题型的正确计数和总分。

【1】获取经过的时间:使用题目规定的时间间隔,将其累加到总用时中。questionBank.get(下标)来通过获取当前问题。

【2】根据问题类型判断答案是否正确:获取用户的选择按钮,检查用户的选择按钮是否等于正确答案,如果是则增加单选正确计数和总分。

【3】每次答题后进行实时校对和得分统计。

(9)定义startExam考试开始方法,初始化考试相关的变量,并显示第一道题目。

(10)定义showNextQuestion方法用于在规定的时间后自动调用 evaluateAnswer 方法评估用户的答案,然后调用 showNextQuestion 方法显示下一道题目。

创建一个 Timer 对象,设置定时器的初始延迟时间为设定的题目时间。再创建一个匿名内部类,实现 ActionListener 接口,用于监听定时器的动作事件。actionPerformed 方法在定时器触发时执行评估用户的答案和显示下一道题目的操作。使用setRepeats(false);:设置定时器在执行完一次动作后不再重复执行。一旦计时器到达设定的时间,将触发 actionPerformed 方法执行相关操作。

  • 定义showNextQuestion方法,用来显示下一道题目。

先检查是否还有下一道题目,如果有获取并显示题目再启动题目计时器,更新当前题目索引。若没有题目了,则调用 endExam 方法结束考试。

(12)定义endExam结束考试方法,通过showMessageDialog显示考试结束窗口,包括各题型的正确数,总得分以及总用时。

  • 在main主方法中运行,使用了 SwingUtilities.invokeLater 来确保 GUI 组件在事件分发线程(Event Dispatch Thread)上创建和处理,以确保线程安全性创建一个匿名的 Runnable 类,实现 run 方法。在 run 方法中创建 ExamModel 实例,作为 GUI 窗口的主要部分。

代码:

package 必实验5;

import java.util.List;

// 定义抽象问题类
abstract class Question {
    private String question;

    public Question(String question) {
        this.question = question;
    }

    public String getQuestion() {
        return question;
    }

    public abstract String getCorrectAnswer();
}

// 定义问题子类单选题类
class SingleChoiceQuestion extends Question {
    private List<String> choices;
    private String correctAnswer;

    public SingleChoiceQuestion(String question, List<String> choices, String correctAnswer) {
        super(question);
        this.choices = choices;
        this.correctAnswer = correctAnswer;
    }

    public List<String> getChoices() {
        return choices;
    }

    @Override
    public String getCorrectAnswer() {
        return correctAnswer;
    }
}

// 定义问题子类多选题类
class MultipleChoiceQuestion extends Question {
    private List<String> choices;
    private List<String> correctAnswers;

    public MultipleChoiceQuestion(String question, List<String> choices, List<String> correctAnswers) {
        super(question);
        this.choices = choices;
        this.correctAnswers = correctAnswers;
    }

    public List<String> getChoices() {
        return choices;
    }

    // 返回多选答案列表(包含多个正确选项)
    public List<String> getCorrectAnswers() {
        return correctAnswers;
    }

    @Override
    public String getCorrectAnswer() {
        return String.join(",", correctAnswers);
    }
}

// 定义问题子类判断对错类
class TrueFalseQuestion extends Question {
    private boolean correct;

    public TrueFalseQuestion(String question, boolean correct) {
        super(question);
        this.correct = correct;
    }

    public boolean isCorrect() {
        return correct;
    }
    
    @Override
    public String getCorrectAnswer() {
        return correct ? "True" : "False";
    }
}

package 必实验5;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Random;
import java.util.Arrays;

// 定义ExamModel 类,作为“JAVA机考”的功能,继承自 JFrame 类,表示考试模型的主窗口
public class ExamModel extends JFrame {
	// 声明所需常量,包括总题数,各种类型题得分数以及问题间隔
	private static final long serialVersionUID = 1L;
	private static final int TOTAL_QUESTIONS = 15;
    private static final int SINGLE_CHOICE_SCORE = 1;
    private static final int MULTIPLE_CHOICE_SCORE = 2;
    private static final int TRUE_FALSE_SCORE = 1;
    private static final int QUESTION_INTERVAL_SECONDS = 20;

    // 声明相关变量,包括单选、多选、判断对错的正确数,总得分以及总时间
    private List<Question> questionBank;
    private int currentQuestionIndex;
    private int singleChoiceCorrectCount;
    private int multipleChoiceCorrectCount;
    private int trueFalseCorrectCount;
    private int totalScore;
    private int totalTime;
    // 定义JLabel 对象,用于显示问题的描述文本
    private JLabel questionLabel;
    // 定义ButtonGroup 对象,用于将单选按钮或复选框组合在一起
    private ButtonGroup answerGroup;
    // 定义JButton 对象,用于用户提交答案
    private JButton submitButton;
    // 定义JPanel 对象,用于容纳用户选择答案的组件,例如单选按钮或复选框。
    private JPanel answerPanel; 

    public ExamModel() {
    	// 初始化问题库
        initializeQuestionBank();
        // 初始化用户界面
        initializeUI();
        //开始考试
        startExam();
    }

    //生成单选题目的方法,包括单选题库10道
    private SingleChoiceQuestion[] generateSingleChoiceQuestion() {
    	SingleChoiceQuestion[] questions = new SingleChoiceQuestion[10];
    	String question1 = "法国的首都是哪里?";
        List<String> choices1 = Arrays.asList("A. Paris", "B. Berlin", "C. Madrid", "D. Rome");
        String correctAnswer1 = "A. Paris"; 
        questions[0] = new SingleChoiceQuestion(question1, choices1, correctAnswer1);
        String question2 = "老师的英语是什么?";
        List<String> choices2 = Arrays.asList("A. Student", "B. Teacher", "C. Picture", "D. Dancer");
        String correctAnswer2 = "B. Teacher"; 
        questions[1] = new SingleChoiceQuestion(question2, choices2, correctAnswer2);
        String question3 = "Good的同义词是什么?";
        List<String> choices3 = Arrays.asList("A. Bad", "B. Worse", "C. Great", "D. Full");
        String correctAnswer3 = "C. Great"; 
        questions[2] = new SingleChoiceQuestion(question3, choices3, correctAnswer3);
        String question4 = "1+5+80-1=?";
        List<String> choices4 = Arrays.asList("A. 88", "B. 86", "C. 84", "D. 85");
        String correctAnswer4 = "D. 85"; 
        questions[3] = new SingleChoiceQuestion(question4, choices4, correctAnswer4);
        String question5 = "圆周率保留两位小数是多少?";
        List<String> choices5 = Arrays.asList("A. 3.14", "B. 3.18", "C. 3.19", "D. 3.15");
        String correctAnswer5 = "A. 3.14"; 
        questions[4] = new SingleChoiceQuestion(question5, choices5, correctAnswer5);
        String question6 = "法国的首都是哪里?";
        List<String> choices6 = Arrays.asList("A. Paris", "B. Berlin", "C. Madrid", "D. Rome");
        String correctAnswer6 = "A. Paris"; 
        questions[5] = new SingleChoiceQuestion(question6, choices6, correctAnswer6);
        String question7 = "老师的英语是什么?";
        List<String> choices7 = Arrays.asList("A. Student", "B. Teacher", "C. Picture", "D. Dancer");
        String correctAnswer7 = "B. Teacher"; 
        questions[6] = new SingleChoiceQuestion(question7, choices7, correctAnswer7);
        String question8 = "Good的同义词是什么?";
        List<String> choices8 = Arrays.asList("A. Bad", "B. Worse", "C. Great", "D. Full");
        String correctAnswer8 = "C. Great"; 
        questions[7] = new SingleChoiceQuestion(question8, choices8, correctAnswer8);
        String question9 = "1+5+80-1=?";
        List<String> choices9 = Arrays.asList("A. 88", "B. 86", "C. 84", "D. 85");
        String correctAnswer9 = "D. 85"; 
        questions[8] = new SingleChoiceQuestion(question9, choices9, correctAnswer9);
        String question10 = "圆周率保留两位小数是多少?";
        List<String> choices10 = Arrays.asList("A. 3.14", "B. 3.18", "C. 3.19", "D. 3.15");
        String correctAnswer10 = "A. 3.14"; 
        questions[9] = new SingleChoiceQuestion(question10, choices10, correctAnswer10);
        return questions;
    }

    //生成多选题目的方法,包括多选题库10道
    private MultipleChoiceQuestion[] generateMultipleChoiceQuestion() {
    	MultipleChoiceQuestion[] questions = new MultipleChoiceQuestion[10];
        String question1 = "哪些编程语言是面向对象的程序语言?";
        List<String> choices1 = Arrays.asList("A. Java", "B. Python", "C. C++", "D. Assembly");
        List<String> correctAnswers1 = Arrays.asList("A. Java", "C. C++"); 
        questions[0]= new MultipleChoiceQuestion(question1, choices1, correctAnswers1);
        String question2 = "哪些是正向词语?";
        List<String> choices2 = Arrays.asList("A. 开心", "B. 快乐", "C. 无语", "D. 生气");
        List<String> correctAnswers2 = Arrays.asList("A. 开心", "B. 快乐"); 
        questions[1]= new MultipleChoiceQuestion(question2, choices2, correctAnswers2);
        String question3 = "哪些是食物?";
        List<String> choices3 = Arrays.asList("A. new", "B.milk ", "C. bread", "D. pipe");
        List<String> correctAnswers3 = Arrays.asList("B.milk", "C. bread"); 
        questions[2]= new MultipleChoiceQuestion(question3, choices3, correctAnswers3);
        String question4 = "田字组词正确的有?";
        List<String> choices4 = Arrays.asList("A. 田野", "B. 田浓", "C. 田地", "D. 田园");
        List<String> correctAnswers4 = Arrays.asList("A. 田野", "C. 田地","D. 田园"); 
        questions[3]= new MultipleChoiceQuestion(question4, choices4, correctAnswers4);
        String question5 = "下面属于甜品的种类有?";
        List<String> choices5 = Arrays.asList("A.香蕉 ", "B. 恰巴塔", "C. 舒芙蕾", "D. 提拉米苏");
        List<String> correctAnswers5 = Arrays.asList("C. 舒芙蕾", "D. 提拉米苏"); 
        questions[4]= new MultipleChoiceQuestion(question5, choices5, correctAnswers5);
        String question6 = "哪些编程语言是面向对象的程序语言?";
        List<String> choices6 = Arrays.asList("A. Java", "B. Python", "C. C++", "D. Assembly");
        List<String> correctAnswers6 = Arrays.asList("A. Java", "C. C++"); 
        questions[5]= new MultipleChoiceQuestion(question6, choices6, correctAnswers6);
        String question7 = "哪些是正向词语?";
        List<String> choices7 = Arrays.asList("A. 开心", "B. 快乐", "C. 无语", "D. 生气");
        List<String> correctAnswers7 = Arrays.asList("A. 开心", "B. 快乐"); 
        questions[6]= new MultipleChoiceQuestion(question7, choices7, correctAnswers7);
        String question8 = "哪些是食物?";
        List<String> choices8 = Arrays.asList("A. new", "B.milk ", "C. bread", "D. pipe");
        List<String> correctAnswers8 = Arrays.asList("B.milk", "C. bread"); 
        questions[7]= new MultipleChoiceQuestion(question8, choices8, correctAnswers8);
        String question9 = "田字组词正确的有?";
        List<String> choices9 = Arrays.asList("A. 田野", "B. 田浓", "C. 田地", "D. 田园");
        List<String> correctAnswers9 = Arrays.asList("A. 田野", "C. 田地","D. 田园"); 
        questions[8]= new MultipleChoiceQuestion(question9, choices9, correctAnswers9);
        String question10 = "下面属于甜品的种类有?";
        List<String> choices10 = Arrays.asList("A.香蕉 ", "B. 恰巴塔", "C. 舒芙蕾", "D. 提拉米苏");
        List<String> correctAnswers10 = Arrays.asList("C. 舒芙蕾", "D. 提拉米苏"); 
        questions[9]= new MultipleChoiceQuestion(question10, choices10, correctAnswers10);
        return questions;
    }

   //生成判断对错选题目的方法,包括判断对错题库10道
    private TrueFalseQuestion[] generateTrueFalseQuestion() {
    	TrueFalseQuestion[] questions = new TrueFalseQuestion[10];
        String question1 = "太阳从西边起. (True/False)";
        boolean correctAnswer1 = false; 
        questions[0]=new TrueFalseQuestion(question1, correctAnswer1);
        String question2 = "人类离不开水. (True/False)";
        boolean correctAnswer2 = true; 
        questions[1]=new TrueFalseQuestion(question2, correctAnswer2);
        String question3 = "水的英语是wate. (True/False)";
        boolean correctAnswer3 = false; 
        questions[2]=new TrueFalseQuestion(question3, correctAnswer3);
        String question4 = "可以躺着玩手机. (True/False)";
        boolean correctAnswer4 = false; 
        questions[3]=new TrueFalseQuestion(question4, correctAnswer4);
        String question5 = "我们要天天运动. (True/False)";
        boolean correctAnswer5 = true; 
        questions[4]=new TrueFalseQuestion(question5, correctAnswer5);
        String question6 = "太阳从西边起. (True/False)";
        boolean correctAnswer6 = false; 
        questions[5]=new TrueFalseQuestion(question6, correctAnswer6);
        String question7 = "人类离不开水. (True/False)";
        boolean correctAnswer7 = true; 
        questions[6]=new TrueFalseQuestion(question7, correctAnswer7);
        String question8 = "水的英语是wate. (True/False)";
        boolean correctAnswer8 = false; 
        questions[7]=new TrueFalseQuestion(question8, correctAnswer8);
        String question9 = "可以躺着玩手机. (True/False)";
        boolean correctAnswer9 = false; 
        questions[8]=new TrueFalseQuestion(question9, correctAnswer9);
        String question10 = "我们要天天运动. (True/False)";
        boolean correctAnswer10 = true; 
        questions[9]=new TrueFalseQuestion(question10, correctAnswer10);
        return questions;
    }
    
    // 从题目数组中随机选择指定数量的题目
    private <T> List<T> getRandomQuestions(T[] questions, int count) {
        List<T> selectedQuestions = new ArrayList<>();
        List<T> availableQuestions = new ArrayList<>(Arrays.asList(questions));

        // 随机选择题目
        Random random = new Random();// 创建一个 Random 对象,用于生成随机数
        for (int i = 0; i < count && !availableQuestions.isEmpty(); i++) {
        	// 设置随机索引,范围是当前可用题目的数量
            int randomIndex = random.nextInt(availableQuestions.size());
            // 将选定的题目添加到 selectedQuestions 列表中
            // 并从可用题目列表中移除,确保不会重复选择同一道题目
            selectedQuestions.add(availableQuestions.remove(randomIndex));
        }

        return selectedQuestions;
    }
    
    // 初始化题库
    private void initializeQuestionBank() {
        questionBank = new ArrayList<>();

        // 从单选题库中随机选择5个题目
        List<SingleChoiceQuestion> singleChoiceQuestions = getRandomQuestions(generateSingleChoiceQuestion(), 5);
        questionBank.addAll(singleChoiceQuestions);

        // 从多选题库中随机选择5个题目
        List<MultipleChoiceQuestion> multipleChoiceQuestions = getRandomQuestions(generateMultipleChoiceQuestion(), 5);
        questionBank.addAll(multipleChoiceQuestions);

        // 从判断对错题库中随机选择5个题目
        List<TrueFalseQuestion> trueFalseQuestions = getRandomQuestions(generateTrueFalseQuestion(), 5);
        questionBank.addAll(trueFalseQuestions);

        // 打乱整个题目的顺序
        java.util.Collections.shuffle(questionBank);
    }

    //  初始化用户界面
    private void initializeUI() {
    	// 设置窗口标题
        setTitle("Java机考");
        //设置窗口的初始大小为宽度 600 像素,高度 400 像素
        setSize(600, 400);
        //设置窗口关闭时默认的操作为终止程序
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //将窗口定位在屏幕中央
        setLocationRelativeTo(null);

        //创建显示问题标签,管理单选按钮或单选框的按钮组,提交按钮
        questionLabel = new JLabel();
        answerGroup = new ButtonGroup();
        submitButton = new JButton("提交");

        //为提交按钮添加一个匿名的事件监听器,定义了在按钮被点击时执行的操作
        submitButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
            	//评估用户的答案和显示下一个问题
                evaluateAnswer();
                showNextQuestion();
            }
        });
       
        // 设置窗口的布局管理器为边界布局
        setLayout(new BorderLayout());
        //问题标签添加到窗口的中央位置
        add(questionLabel, BorderLayout.CENTER);
        // 提交按钮添加到窗口的下册位置
        add(submitButton, BorderLayout.SOUTH);
        // 创建一个面板用于放置答案选项,初始时为空,放在窗口的右侧位置
        answerPanel = new JPanel();
        add(answerPanel, BorderLayout.EAST);
    }

    // 考试开始
    private void startExam() {
        currentQuestionIndex = 0;
        singleChoiceCorrectCount = 0;
        multipleChoiceCorrectCount = 0;
        trueFalseCorrectCount = 0;
        totalScore = 0;
        totalTime = 0;

        showNextQuestion();
    }

    // 显示下一道题目
    private void showNextQuestion() {
    	// 比较当前题目索引和题目总数,检查是否还有未显示的题目
        if (currentQuestionIndex < TOTAL_QUESTIONS) {
        	// 从题库中获取当前题目
            Question question = questionBank.get(currentQuestionIndex);
            displayQuestion(question);
            //启动题目计时器
            startQuestionTimer();
            currentQuestionIndex++;
        } else {
        	//如果所有题目都已显示完毕,则调用 endExam 方法结束考试
            endExam();
        }
    }

    //定义displayQuestion方法,用于在用户界面上显示问题和答案选项
    private void displayQuestion(Question question) {
    	//将问题标签的文本设置为当前问题的文本
        questionLabel.setText(question.getQuestion());
        //清除选择和移除组件
        answerGroup.clearSelection();
        answerPanel.removeAll();

        // 根据问题类型添加答案选项组件
        if (question instanceof SingleChoiceQuestion) {
        	//遍历单选题的选项,为每个选项创建一个单选按钮,并将其添加到按钮组和答案面板中
            SingleChoiceQuestion singleChoiceQuestion = (SingleChoiceQuestion) question;
            for (String choice : singleChoiceQuestion.getChoices()) {
                JRadioButton radioButton = new JRadioButton(choice);
                answerGroup.add(radioButton);
                answerPanel.add(radioButton);
            }
        } else if (question instanceof MultipleChoiceQuestion) {
            MultipleChoiceQuestion multipleChoiceQuestion = (MultipleChoiceQuestion) question;
            // 遍历多选题的选项,为每个选项创建一个复选框,并将其添加到答案面板中
            for (String choice : multipleChoiceQuestion.getChoices()) {
                JCheckBox checkBox = new JCheckBox(choice);
                answerPanel.add(checkBox);
            }
        } else if (question instanceof TrueFalseQuestion) {
        	// 创建 "True" 和 "False" 两个单选按钮,并将它们添加到按钮组和答案面板中
            JRadioButton trueRadioButton = new JRadioButton("True");
            JRadioButton falseRadioButton = new JRadioButton("False");
            answerGroup.add(trueRadioButton);
            answerGroup.add(falseRadioButton);
            answerPanel.add(trueRadioButton);
            answerPanel.add(falseRadioButton);
        }

        // 启用提交按钮,使用户可以提交答案
        submitButton.setEnabled(true);
        // 重新验证界面,确保新的组件布局得到应用
        revalidate();
        //重绘界面,使新的组件可见
        repaint();
    }

    //启动一个定时器
    private void startQuestionTimer() {
    	//建一个 Timer 对象,设置定时器的初始延迟时间为即设定的题目时间
    	// 创建一个匿名内部类,实现 ActionListener 接口,用于监听定时器的动作事件
        Timer timer = new Timer(QUESTION_INTERVAL_SECONDS * 1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
            	//在定时器触发时执行评估答案和显示下一道题的操作
                evaluateAnswer();
                showNextQuestion();
            }
        });
        // 设置定时器在执行完一次动作后不再重复执行
        timer.setRepeats(false);
        // 启动定时器,开始计时
        timer.start();
    }

    // 定义valuateAnswer根据用户选择的答案和当前问题的正确答案,更新单选、多选、判断对错题型的正确计数和总分
    private void evaluateAnswer() {
    	// 题目规定的时间间隔
        int elapsedTime = QUESTION_INTERVAL_SECONDS;
        // 答题用时累加到总用时
        totalTime += elapsedTime;

        //当前正在评估的问题,通过 currentQuestionIndex - 1 来获得上一个问题的索引
        Question currentQuestion = questionBank.get(currentQuestionIndex - 1);

        // 根据问题类型判断答案是否正确
        if (currentQuestion instanceof SingleChoiceQuestion) {
            SingleChoiceQuestion singleChoiceQuestion = (SingleChoiceQuestion) currentQuestion;
            // 获取用户选择的单选按钮
            JRadioButton selectedRadioButton = getSelectedRadioButton();
            // 检查用户选择的单选按钮是否等于单选题的正确答案,如果是则增加单选正确计数和总分
            if (selectedRadioButton != null && selectedRadioButton.getText().equals(singleChoiceQuestion.getCorrectAnswer())) {
                singleChoiceCorrectCount++;
                totalScore += SINGLE_CHOICE_SCORE;
            }
        } else if (currentQuestion instanceof MultipleChoiceQuestion) {
            MultipleChoiceQuestion multipleChoiceQuestion = (MultipleChoiceQuestion) currentQuestion;
            // 获取用户选择的复选框
            List<String> selectedAnswers = getSelectedCheckboxes();
            // 检查用户选择的复选框是否包含所有多选题的正确答案,如果是则增加多选正确计数和总分
            if (selectedAnswers != null && selectedAnswers.containsAll(multipleChoiceQuestion.getCorrectAnswers())) {
                multipleChoiceCorrectCount++;
                totalScore += MULTIPLE_CHOICE_SCORE;
            }
   
        } else if (currentQuestion instanceof TrueFalseQuestion) {
            TrueFalseQuestion trueFalseQuestion = (TrueFalseQuestion) currentQuestion;
            // 获取用户选择的对错按钮
            JRadioButton selectedRadioButton = getSelectedRadioButton();
            // 根据判断对错题的正确性和用户选择的对错按钮是否匹配,如果是则增加判断对错正确计数和总分。
            if (selectedRadioButton != null && (trueFalseQuestion.isCorrect() && selectedRadioButton.getText().equals("True") ||
                    !trueFalseQuestion.isCorrect() && selectedRadioButton.getText().equals("False"))) {
                trueFalseCorrectCount++;
                totalScore += TRUE_FALSE_SCORE;
            }
        }

        // 每次答题后进行实时校对和得分统计
        submitButton.setEnabled(false);
        System.out.println("问题 #" + currentQuestionIndex +
                " - 正确答案: " + currentQuestion.getCorrectAnswer() +
                " - 所用时间: " + elapsedTime + " 秒" +
                " - 得分: " + totalScore);
    }

    //结束考试
    private void endExam() {
        JOptionPane.showMessageDialog(this, "考试完成!\n" +
                "总得分: " + totalScore +
                "\n单选题正确数: " + singleChoiceCorrectCount +
                "\n多选题正确数: " + multipleChoiceCorrectCount +
                "\n判断对错正确数: " + trueFalseCorrectCount +
                "\n总用时: " + totalTime + "秒" );
        System.exit(0);
    }

    // 获取用户选择按钮的答案的方法
    private JRadioButton getSelectedRadioButton() {
    	//通过 answerGroup 获取所有的按钮元素
        for (Enumeration<AbstractButton> buttons = answerGroup.getElements(); buttons.hasMoreElements(); ) {
            AbstractButton button = buttons.nextElement();//逐个迭代获取按钮
            //判断是否被选取
            if (button.isSelected() && button instanceof JRadioButton) {
                return (JRadioButton) button;
            }
        }
        return null;
    }

    // 获取用户选择复选框的答案的方法
    private List<String> getSelectedCheckboxes() {
    	// 创建一个字符串列表,用于存储用户选择的复选框答案
        List<String> selectedAnswers = new ArrayList<>();
        //通过 answerGroup 获取所有的按钮元素
        for (Enumeration<AbstractButton> buttons = answerGroup.getElements(); buttons.hasMoreElements(); ) {
            AbstractButton button = buttons.nextElement();
            //检查按钮是否被选中
            if (button.isSelected()) {
                selectedAnswers.add(button.getText());
            }
        }
        // 如果选中答案列表为空,返回 null;否则返回包含选中答案的列表
        return selectedAnswers.isEmpty() ? null : selectedAnswers;
    }

    // 主方法运行
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ExamModel().setVisible(true);
            }
        });
    }
}

运行结果:

(1)多选题:

(2)判断对错题:

(3)单选题:

(4)考试结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值