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线程,造成界面卡顿。
修复方案
- 使用AWT
Timer替代paint方法中的sleep和repaint,单独处理计时器更新,避免阻塞UI线程。 - 将图像封装为
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...
相关产品推荐
相关产品推荐

