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

AWT测验应用问题:按钮点击超限与图像重复重绘

解决方案

问题1:快速点击Next导致数组越界

原因

当前代码仅在count == 8时禁用Next按钮,但快速连续点击时,按钮被禁用前可能多次触发点击事件,导致count被递增至超过9(数组最大索引),访问useranswers[count]时触发数组越界异常。

修复方案

在actionPerformed的Next分支中,先判断count是否小于9,仅当count < 9时才执行答题保存、count递增和加载下一题操作;同时调整按钮状态更新逻辑,确保最后一题(count=9)时Next按钮处于禁用状态。

问题2:图像每秒重复重绘

原因

原代码在paint方法中每秒调用repaint(),导致整个界面包括图像被重复绘制,且paint方法中调用Thread.sleep(1000)会阻塞UI线程,造成界面卡顿。

修复方案

  1. 使用AWT Timer替代paint方法中的sleep和repaint,单独处理计时器更新,避免阻塞UI线程。
  2. 将图像封装为Label组件添加到界面,而非在paint方法中绘制,这样图像只会渲染一次,无需重复重绘。

修改后的完整代码
package com.shivam;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class QuizFrame extends Frame implements ActionListener {
    String[][] questions;
    String[][] answers;
    String[][] useranswers = new String[10][1];
    Label qno, question, timerLabel;
    Checkbox opt1, opt2, opt3, opt4;
    CheckboxGroup groupoptions;
    Button next, submit;
    Image image;
    public int timer = 15;
    public int ans_given = 0;
    public int count = 0;
    public int score = 0;
    String name;
    private Timer timerThread;

    QuizFrame(String name, QuizRepository quizRepository) {
        count = 0;
        this.name = name;
        setTitle("QuizApp - Quiz");
        setBackground(new Color(42, 20, 66));
        setForeground(Color.WHITE);
        setLayout(null);

        questions = quizRepository.getQuestions();
        answers = quizRepository.getAnswers();

        // 计时器Label,替代paint中的绘制
        timerLabel = new Label("Time left - 15 seconds");
        timerLabel.setBounds(600, 200, 300, 30);
        timerLabel.setFont(new Font("Tahoma", Font.BOLD, 25));
        timerLabel.setForeground(Color.RED);
        add(timerLabel);

        // 图像用Label展示,避免重复绘制
        image = Toolkit.getDefaultToolkit().getImage("src/resources/boy.png");
        MediaTracker tracker = new MediaTracker(this);
        tracker.addImage(image, 0);
        try {
            tracker.waitForID(0);
        } catch (InterruptedException ae) {
            System.out.println("Exception occurred while loading image...");
        }
        Label imageLabel = new Label(new ImageIcon(image));
        imageLabel.setBounds(950, 300, image.getWidth(this), image.getHeight(this));
        add(imageLabel);

        qno = new Label();
        qno.setBounds(350, 280, 40, 30);
        qno.setFont(new Font("Tahoma", Font.PLAIN, 24));
        add(qno);

        question = new Label();
        question.setBounds(410, 280, 850, 30);
        question.setFont(new Font("Tahoma", Font.PLAIN, 24));
        add(question);

        groupoptions = new CheckboxGroup();
        opt1 = new Checkbox();
        opt1.setCheckboxGroup(groupoptions);
        opt1.setBounds(420, 320, 300, 30);
        opt1.setFont(new Font("Dialog", Font.PLAIN, 20));
        add(opt1);

        opt2 = new Checkbox();
        opt2.setCheckboxGroup(groupoptions);
        opt2.setBounds(420, 360, 300, 30);
        opt2.setFont(new Font("Dialog", Font.PLAIN, 20));
        add(opt2);

        opt3 = new Checkbox();
        opt3.setBounds(420, 400, 300, 30);
        opt3.setCheckboxGroup(groupoptions);
        opt3.setFont(new Font("Dialog", Font.PLAIN, 20));
        add(opt3);

        opt4 = new Checkbox();
        opt4.setBounds(420, 440, 300, 30);
        opt4.setCheckboxGroup(groupoptions);
        opt4.setFont(new Font("Dialog", Font.PLAIN, 20));
        add(opt4);

        next = new Button("Next");
        next.setBounds(550, 500, 150, 40);
        next.setFont(new Font("Tahoma", Font.PLAIN, 22));
        next.setBackground(new Color(30, 144, 255));
        next.setForeground(Color.WHITE);
        next.addActionListener(this);
        add(next);

        submit = new Button("Submit");
        submit.setBounds(800, 500, 150, 40);
        submit.setFont(new Font("Tahoma", Font.PLAIN, 22));
        submit.setBackground(new Color(129, 131, 129));
        submit.setForeground(Color.WHITE);
        submit.addActionListener(this);
        submit.setEnabled(false);
        add(submit);

        start(count);
        setExtendedState(Frame.MAXIMIZED_BOTH);

        // 初始化计时器线程
        timerThread = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (timer > 0) {
                    timer--;
                    timerLabel.setText("Time left - " + timer + " seconds");
                } else {
                    timerThread.stop();
                    timerLabel.setText("Times up!!");
                    handleTimeUp();
                }
            }
        });
        timerThread.start();

        // 添加关闭窗口监听,停止计时器
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                timerThread.stop();
                dispose();
            }
        });

        setVisible(true);
    }

    private void handleTimeUp() {
        ans_given = 1;
        timer = 15;
        opt1.setEnabled(true);
        opt2.setEnabled(true);
        opt3.setEnabled(true);
        opt4.setEnabled(true);

        if (count == 9) {
            // 最后一题超时,提交
            saveCurrentAnswer();
            calculateScore();
            setVisible(false);
            new ResultFrame(name, score);
            System.out.println("Score : " + score);
        } else {
            // 切换到下一题
            saveCurrentAnswer();
            count++;
            start(count);
            updateButtonStates();
            timerThread.start();
        }
    }

    private void saveCurrentAnswer() {
        if (groupoptions.getSelectedCheckbox() == null) {
            useranswers[count][0] = "";
        } else {
            useranswers[count][0] = groupoptions.getSelectedCheckbox().getLabel();
        }
    }

    private void calculateScore() {
        score = 0;
        for (int i = 0; i < useranswers.length; i++) {
            if (useranswers[i][0].equals(answers[i][1])) {
                score += 10;
            }
        }
    }

    private void updateButtonStates() {
        if (count >= 9) {
            next.setEnabled(false);
            next.setBackground(new Color(129, 131, 129));
            submit.setEnabled(true);
            submit.setBackground(new Color(104, 239, 66));
        } else {
            next.setEnabled(true);
            next.setBackground(new Color(30, 144, 255));
            submit.setEnabled(false);
            submit.setBackground(new Color(129, 131, 129));
        }
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        if (ae.getSource() == next) {
            if (count >= 9) {
                return; // 最后一题,禁止点击Next
            }
            ans_given = 1;
            saveCurrentAnswer();
            count++;
            start(count);
            updateButtonStates();
            // 重置计时器
            timer = 15;
            timerLabel.setText("Time left - 15 seconds");
            timerThread.restart();
        } else if (ae.getSource() == submit) {
            ans_given = 1;
            saveCurrentAnswer();
            calculateScore();
            timerThread.stop();
            setVisible(false);
            new ResultFrame(name, score);
            System.out.println("Score : " + score);
        }
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        // 不再在这里绘制图像和计时器,改用组件实现
    }

    public void start(int count) {
        if (count <= 9) {
            qno.setText((count + 1) + ". ");
            question.setText(questions[count][0]);
            opt1.setLabel(questions[count][1]);
            opt2.setLabel(questions[count][2]);
            opt3.setLabel(questions[count][3]);
            opt4.setLabel(questions[count][4]);
            groupoptions.setSelectedCheckbox(null);
        }
    }
}

内容的提问来源于stack exchange,提问作者Shivam...

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:17:33