1

I'm writing a program that has a quiz element, and when the user gets an answer wrong, feedback is given. The question JFrame is made of a JLabel that has the actual question, and 4 JRadioButtons that have the different options (named rad1, rad2, rad3, rad4). What I'm trying to do is if the user gets an asnswer wrong, the radio button with the correct answer's background colour turns green and the radio button with the answer that the user gave's background turns red.

Here's the FOR loop that I'm using to figure out which of the answers is correct:

private void btnSubmitActionPerformed(java.awt.event.ActionEvent evt) {                                          
    System.out.println("Submit Clicked");
    //figures out what choice the user selected
    String correctAnswer = questions.get(current).getAnswer();
    int numChoice = -1;
    String choice = "";
    boolean answered = false;

    if (rad1.isSelected()) {
        numChoice = 0;
        answered = true;
        choice = rad1.getText();
    } else if (rad2.isSelected()) {
        numChoice = 1;
        answered = true;
        choice = rad2.getText();
    } else if (rad3.isSelected()) {
        numChoice = 2;
        answered = true;
        choice = rad3.getText();
    } else if (rad4.isSelected()) {
        numChoice = 3;
        answered = true;
        choice = rad4.getText();
    } else { //user didn't pick a choice
        JOptionPane.showMessageDialog(null, "You didn't answer the question, try again!");
    }

    if (choice.equals(correctAnswer)) {
        score++;
        System.out.println("score++");
    } else {
        //figures out which of the answers was correct
        rad1.setBackground(Color.RED);
        for (int i = 0; i < 4; i++) {
            if (questions.get(current).getChoices()[i].equals(correctAnswer)) {
                System.out.println(correctAnswer);
                System.out.println(i);
                //me trying to see if it will change if I put it outside the switch
                //confirmed that it will not.
                rad1.setBackground(Color.RED);
                switch (i) {
                    case 0:
                        rad1.setBackground(new Color(51, 204, 51));
                        break;
                    case 1:
                        rad2.setBackground(new Color(51, 204, 51));
                        break;
                    case 2:
                        rad3.setBackground(new Color(51, 204, 51));
                        break;
                    case 3:
                        rad4.setBackground(new Color(51, 204, 51));
                        break;
                }
                break;
            }

        }
        switch (numChoice) {
            case 0:
                rad1.setBackground(new Color(153, 0, 0));
                break;
            case 1:
                rad2.setBackground(new Color(153, 0, 0));
                break;
            case 2:
                rad3.setBackground(new Color(153, 0, 0));
                break;
            case 3:
                rad4.setBackground(new Color(153, 0, 0));
                break;
        }
    }
    //loads next question


    //loads the next question
    if (current < 10) {
        updateFrame();
    } else {
        //ends the quiz
    }
}                    

I've been playing around with the .setBackground() method for a while, and if I put print statements in the case blocks, they execute, but the colouring doesn't happen. Is there something dumb that I'm missing?

Thanks

EDIT: Added more code to see that the FOR loop is within the btnSubmitActionPerformed() method. When the user clicks the button, their answer is to be judged and the colour of the radio button is to be changed.

  • Consider providing a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses – MadProgrammer Dec 08 '15 at 23:37

2 Answers2

1

Two immediate things jump to mind:

  1. Where is the code you posted being called from? Making UI changes outside of the Swing worker thread is sort of undefined. Sometimes the right thing will happen, other times not.
  2. I've never tried to set colors on radio buttons, but it seems likely that they don't have a background.

Try setting some other property, like size, just to see if you get a result. If so, then the problem is that radio buttons don't have a background and you'll have to come up with another design. If nothing happens, then it's probably the first problem.

MattPutnam
  • 2,927
  • 2
  • 17
  • 23
1

You look to have code that is overly and unnecessarily complex. Myself, I'd try to "OOP-ify" things to reduce cyclomatic complexity and have

  • A nonGUI Question class,
  • with a String field for questionText,
  • with a String field for correctAnswer,
  • with a List<String> for incorrectAnswers.
  • I'd give it a method, say public List<String> getShuffledAnswers() to return a List of Strings with all answers, both correct and incorrect, shuffled in their own list,
  • A boolean method to testAnswer(String test), and return true of the test equals the correctAnswer.

I'd then create a JPanel called QuestionPanel

  • that has a Question field
  • that displays the information of a single Question object, including the questionText in the JLabel and all the shuffled answers in JRadioButtons.
  • It would have methods for getting the selected JRadioButton and for getting the Question,
  • And a method for setting making a JRadioButtons background non-opaque when need be, by calling `setOpaque(false)
  • And a method that allows the calling code to set the background of select JRadioButtons with a correct answer color or incorrect answer color.

For example:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class TestQuestions extends JPanel {
    private static final Question TEST_QUESTION = new Question("Select the Correct Answer", "This answer is correct", 
            "Incorrect Answer 1", "Incorrect Answer 2", "Incorrect Answer 3");
    private QuestionPanel questionPanel = new QuestionPanel();

    public TestQuestions() {
        questionPanel.setQuestion(TEST_QUESTION);
        JButton testAnswerBtn = new JButton(new AbstractAction("Test Answer") {

            @Override
            public void actionPerformed(ActionEvent e) {
                boolean isCorrect = questionPanel.isCorrectAnswerSelected();
                String message = "";
                if (isCorrect) {
                    message = "Correct answer selected!";
                } else {
                    message = "Incorrect answer selected!";                    
                }
                JOptionPane.showMessageDialog(TestQuestions.this, message);
                questionPanel.displayCorrectWrongAnswers();
            }
        });
        JButton clearAllBtn = new JButton(new AbstractAction("Clear All") {

            @Override
            public void actionPerformed(ActionEvent e) {
                questionPanel.clearAll();
                questionPanel.clearSelection();
            }
        });

        JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        btnPanel.add(testAnswerBtn);
        btnPanel.add(clearAllBtn);

        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        setLayout(new BorderLayout(5, 5));
        add(questionPanel, BorderLayout.CENTER);
        add(btnPanel, BorderLayout.PAGE_END);
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("TestQuestions");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new TestQuestions());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

@SuppressWarnings("serial")
class QuestionPanel extends JPanel {
    private static final Color CORRECT_ANSWER_SELECTED_COLOR = new Color(151, 255, 151);
    private static final Color CORRECT_ANSWER_NOT_SELECTED_COLOR = new Color(151,151, 255);
    private static final Color INCORRECT_ANSWER_SELECTED_COLOR = new Color(255, 151, 151);
    private Question question;
    private JLabel questionTextLabel = new JLabel();
    private List<JRadioButton> answerButtonList = new ArrayList<>();
    private JPanel answerPanel = new JPanel(new GridLayout(0, 1));
    private ButtonGroup buttonGroup = new ButtonGroup();

    public QuestionPanel() {
        setLayout(new BorderLayout());
        add(questionTextLabel, BorderLayout.PAGE_START);
        add(answerPanel, BorderLayout.CENTER);
    }

    public void setQuestion(Question question) {
        this.question = question;
        questionTextLabel.setText(question.getQuestionText());

        answerPanel.removeAll();
        answerButtonList.clear();
        buttonGroup = new ButtonGroup();

        for (String answer : question.getShuffledAnswers()) {
            JRadioButton rBtn = new JRadioButton(answer);
            rBtn.setActionCommand(answer);
            answerButtonList.add(rBtn);
            buttonGroup.add(rBtn);
            answerPanel.add(rBtn);
        }
    }

    public boolean isCorrectAnswerSelected() {
        ButtonModel model = buttonGroup.getSelection();
        if (model == null) {
            return false; // nothing selected
        } else {
            return question.checkAnswer(model.getActionCommand());
        }
    }

    public void clearAll() {
        for (JRadioButton jRadioButton : answerButtonList) {
            jRadioButton.setOpaque(false);
            jRadioButton.setBackground(null);
        }
    }

    public void clearSelection() {
        buttonGroup.clearSelection();
    }

    public void displayCorrectWrongAnswers() {
        clearAll();
        for (JRadioButton jRadioButton : answerButtonList) {
            if (jRadioButton.isSelected()) {
                jRadioButton.setOpaque(true);
                if (question.checkAnswer(jRadioButton.getActionCommand())) {
                    jRadioButton.setBackground(CORRECT_ANSWER_SELECTED_COLOR);
                } else {
                    jRadioButton.setBackground(CORRECT_ANSWER_NOT_SELECTED_COLOR);
                }
            } else if (question.checkAnswer(jRadioButton.getActionCommand())) {
                jRadioButton.setOpaque(true);
                jRadioButton.setBackground(INCORRECT_ANSWER_SELECTED_COLOR);
            }
        }
    }

}

class Question {
    private String questionText;
    private String correctAnswer;
    private List<String> incorrectAnswerList = new ArrayList<>();
    public Question(String questionText, String correctAnswer, String... incorrectAnswers) {
        this.questionText = questionText;
        this.correctAnswer = correctAnswer;
        for (String incorrectAnswer : incorrectAnswers) {
            incorrectAnswerList.add(incorrectAnswer);
        }
    }

    public String getQuestionText() {
        return questionText;
    }

    public String getCorrectAnswer() {
        return correctAnswer;
    }

    public List<String> getShuffledAnswers() {
        List<String> answers = new ArrayList<>(incorrectAnswerList);
        answers.add(correctAnswer);
        Collections.shuffle(answers);
        return answers;
    }

    public boolean checkAnswer(String test) {
        return correctAnswer.equalsIgnoreCase(test);
    }

}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Hey, I appreciate all the help you've given me. I just happened to stumble over a solution though. It seems like I was messing around too much with break; statements and switch's. Thanks for the suggestions! – Sam Macpherson Dec 09 '15 at 00:07
  • well, I ended up not following through with it and changing the way the form works as a result. But what I found was that if I added JOptionPane.showMessageDialog's immediately after the radio button was supposed to change color, they would change correctly. Removing the JOptionPane statements causes them to not work. Bizarre I thought. – Sam Macpherson Dec 11 '15 at 04:41