Search code examples
javaswingjradiobutton

.setBackground() method is not working for JRadioButton


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.


Solution

  • 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);
        }
    
    }