0

My application is a Mutliple choice quiz. Right now there are only two questions so i can test the logic, but after I figure it out ill add up to 100. Really I have a new Frame with buttons added to a panel and then the panel added to the JFrame. I then use nextQuestion() method to allow me to go through multiple questions as long as there are questions left.and there is also a timer that i through in their that gives a time for each question, 10 seconds.

        protected void nextQuestion() {
            timer.stop();
            currentQuestion++;
            if (currentQuestion >= quiz.size()) {
                cardLayout.show(QuestionsPanel, "last");
                next.setEnabled(false);
                //Show however many correct after last question. 
                //iterate on the collection to count the selected radio buttons
                //What im confused about is really how do i tell the program which (options) are right or wrong. 
                //and if i can do that how do i only count the correct ones. 
                //or for example do i have to take the total questions and subtract by the ones they didnt choose? 
                //a code example on how to do this would be great. 
            } else {
                cardLayout.show(QuestionsPanel, Integer.toString(currentQuestion));
                startTime = null;
                next.setText("Next");
                next.setEnabled(true);
                timer.start();
            }
        }



    public interface Question {

        public String getPrompt();

        public String getCorrectAnswer();

        public String[] getOptions();

        public String getUserResponse();

        public void setUserResponse(String response);

        public boolean isCorrect();
    }

    public class ChoiceQuestion implements Question {

        private final String prompt;
        private final String correctAnswer;
        private final String[] options;

        private String userResponse;

        public ChoiceQuestion(String prompt, String correctAnswer, String... options) {
            this.prompt = prompt;
            this.correctAnswer = correctAnswer;
            this.options = options;
        }

        @Override
        public String getPrompt() {
            return prompt;
        }

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

        @Override
        public String[] getOptions() {
            return options;
        }

        @Override
        public String getUserResponse() {
            return userResponse;
        }

        @Override
        public void setUserResponse(String response) {
            userResponse = response;
        }

        @Override
        public boolean isCorrect() {
            return getCorrectAnswer().equals(getUserResponse());
        }
    }

    public class QuestionPane extends JPanel {

        private Question question;

        public QuestionPane(Question question) {
            this.question = question;

            setLayout(new BorderLayout());

            JLabel prompt = new JLabel("<html><b>" + question.getPrompt() + "</b></html>");
            prompt.setHorizontalAlignment(JLabel.LEFT);

            add(prompt, BorderLayout.NORTH);

            JPanel guesses = new JPanel(new GridBagLayout());
            guesses.setBorder(new EmptyBorder(10,10,10,10));
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.weightx = 1;
            gbc.anchor = GridBagConstraints.WEST;

            List<String> options = new ArrayList<>(Arrays.asList(question.getOptions()));
            options.add(question.getCorrectAnswer());
            Collections.sort(options);

            ButtonGroup bg = new ButtonGroup();
            for (String option : options) {
                JRadioButton btn = new JRadioButton(option);
                bg.add(btn);

                guesses.add(btn, gbc);
            }

            add(guesses);

        }

        public Question getQuestion() {
            return question;
        }

        public class ActionHandler implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent e) {
                getQuestion().setUserResponse(e.getActionCommand());
            }

        }

    }

}

SO really i just have an issue with doing that small if else code block. If you guys could help me out. I got some ideas about iterating a collection although i have no idea how to do that.These are just the classes im using and the method i am having a problem with.

  • You could use a simple naming convention for the `CardLayout` (ie `q1`, `q2` etc) and simply keep a simple pointer to the current question. I'd be easier enough then to determine if you're at the start, end or somewhere in the middle of the quiz – MadProgrammer Mar 31 '16 at 07:22
  • Which was demonstrated in the `QuizPanel` from the [same question](http://stackoverflow.com/questions/30925564/why-is-my-jlabel-not-showing-up/30926625#30926625) you got the basic code structure from ... `cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion));`... – MadProgrammer Mar 31 '16 at 07:24
  • ok sorry about that. yes i used the basic code structure i was just wondering since ive been trying for the past two hours to make this quiz functional how do you do it?. is it loop the radio buttons and use is.selected() or use a collecter? – SassyRegards201 Mar 31 '16 at 08:00
  • @MadProgrammer what will keeping a pointer do to the program. would you not rather have it so it checks what buttons were clicked compare it to a correct answer and print score. im not sure im very bad at this logic thing. anyhelp would be great. – SassyRegards201 Mar 31 '16 at 08:25
  • Not really, you can use the `currentQuestion` value to ask the `Quiz` for the `Question` at the current point and check it's `isCorrect` value before moving onto the next `Question`. So in the `nextQuestion` method, you could check before `currentQuestion++`, but you need to verify that the `currentQuestion` is between `0` and the expected number of questions, this way, you could keep a running tally – MadProgrammer Mar 31 '16 at 09:25
  • @MadProgammer so it would be in the if else statement after current question. – SassyRegards201 Mar 31 '16 at 13:41
  • @MadProgrammer currentQuestion > = quiz.size; "how would i ask teh quiz for the question at the current piont." and to check its isCorrect i would just do whatever the question was marked set .equals(isCorrect()); ? – SassyRegards201 Mar 31 '16 at 13:49
  • You have the `currentQuestion`, you have a `List` of `Question`s (`quiz`), in the order they appear. There is a direct correlation between the two. `Question` has a simple `isCorrect` method which returns `true` or `false`, you simply need to check it and take appropriate action based on the return result – MadProgrammer Mar 31 '16 at 18:42

2 Answers2

1

So really simply, when nextQuestion is called, you want to check to see if the currentQuestion is correct or not

private int correctAnswers = 0;
//...
protected void nextQuestion() {
    timer.stop();
    if (currentQuestion >= 0 && currentQuestion < quiz.size()) {
        Question question = quiz.get(currentQuestion);
        if (question.isCorrect()) {
            correctAnswers++;
        }
    }
    currentQuestion++;
    if (currentQuestion >= quiz.size()) {
        cardLayout.show(panelOfQuestions, "last");
        next.setEnabled(false);
    } else {
        cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion));
        startTime = null;
        next.setText("Next");
        next.setEnabled(true);
        timer.start();
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
-1

Here is an example solution for your problem. Is exactly your original code, with a couple of modifications. The key is to understand that you have to relate at any moment the selected answer and fill the "userResponse" field of the Choice Question.

It seems obvious that the best place to set this is when user press "next" button. You check the radio button selected and fill the ChoiseQuestion accordingly.

At last, just manage the quiz List to check how many correct results there are. In my example, the result is printed on the console.

public class QuizMain {

public static void main(String[] args) {
    new QuizMain();
}

public QuizMain() {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                ex.printStackTrace();
            }

            List<Question> quiz = new ArrayList<>(5);
            // Couple of conceptual mistakes here.... 
            quiz.add(new ChoiceQuestion("Where is Japan Located?", "Asia", "North America", "Africa", "Europe", "Asia"));
            // There was a mistake, correct answer is 2
            // quiz.add(new ChoiceQuestion("1 + 1:", "2", "4", "3", "1"));
            quiz.add(new ChoiceQuestion("1 + 1:", "2", "4", "3", "2", "1"));

            JFrame frame = new JFrame("QUIZ TIME!");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new QuizPane(quiz));
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}

public class QuizPane extends JPanel {

    private List<Question> quiz;

    private long countdown = 10;
    private Timer timer;
    private JButton next;
    private JButton intro;


    private CardLayout cardLayout;
    private int currentQuestion;

    private JPanel QuestionsPanel;

    private Long startTime;

    public QuizPane(List<Question> quiz) {
        this.quiz = quiz;
        cardLayout = new CardLayout();
        QuestionsPanel = new JPanel(cardLayout);
        QuestionsPanel.setBorder(new EmptyBorder(40,45,40,45));

        JButton start = new JButton("Start");
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                currentQuestion = -1;
                nextQuestion();
                timer.start();
            }
        });

        JButton intro = new JButton("Instructions");
        intro.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            instructionBox();
          }
        });


        JPanel mainPanel = new JPanel(new GridBagLayout());
        mainPanel.add(start);
        mainPanel.add(intro);
        QuestionsPanel.add(mainPanel, "start");


        for (int index = 0; index < quiz.size(); index++) {
            Question question = quiz.get(index);
            QuestionPane pane = new QuestionPane(question);
            question.setButtonGroup(pane.getButtonGroup());
            QuestionsPanel.add(pane, Integer.toString(index));
        }
        QuestionsPanel.add(new JLabel("You have finished the Quiz"), "last");
        currentQuestion = 0;
        cardLayout.show(QuestionsPanel, "Start");

        setLayout(new BorderLayout());
        add(QuestionsPanel);

        JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        next = new JButton("Next");
        buttonPane.add(next);
        next.setEnabled(false);

        add(buttonPane, BorderLayout.SOUTH);

        next.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                nextQuestion();
            }
        });

        timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (startTime == null) {
                    startTime = System.currentTimeMillis();
                }
                long duration = (System.currentTimeMillis() - startTime) / 1000;
                if (duration >= countdown) {
                    nextQuestion();
                } else {
                    long timeLeft = countdown - duration;
                    next.setText("Next (" + timeLeft + ")");
                    next.repaint();
                }
            }
        });
    }

    protected void nextQuestion() {
        // store the selected answer for each question
        if (currentQuestion >= 0 && currentQuestion < quiz.size() ) {
            Question currentQObject = quiz.get(currentQuestion);
            if (currentQObject != null) {
                currentQObject.setUserResponse(getSelected(currentQObject.getButtonGroup()));
            }
        }
        timer.stop();
        currentQuestion++;
        if (currentQuestion >= quiz.size()) {
            cardLayout.show(QuestionsPanel, "last");
            next.setEnabled(false);
            //Show however many correct after last question. 
            //iterate on the collection to count the selected radio buttons
            //What im confused about is really how do i tell the program which (options) are right or wrong. 
            //and if i can do that how do i only count the correct ones. 
            //or for example do i have to take the total questions and subtract by the ones they didnt choose? 
            //a code example on how to do this would be great.

            // Just iterate over quiz list to check if answers are correct:
            int totalCorrect = 0;
            for (Question q : quiz) {
                if (q.isCorrect()) { 
                    totalCorrect++;
                }
            }

            // Show Corrects any way....
            System.out.println("Total correct responses: " + totalCorrect);

        } else {
            cardLayout.show(QuestionsPanel, Integer.toString(currentQuestion));
            startTime = null;
            next.setText("Next");
            next.setEnabled(true);
            timer.start();
        }
    }

    private String getSelected(ButtonGroup buttonGroup) {
        JRadioButton selectedRadio = null;
        Enumeration e = buttonGroup.getElements();
        while (e.hasMoreElements()) {
            JRadioButton rad = (JRadioButton) e.nextElement();
            if (rad.isSelected()) {
                selectedRadio = rad;
                break;
            }
        }
        return selectedRadio.getText();
    }

    protected void instructionBox() {
        JOptionPane.showMessageDialog(null,"<html><b><div width='111px' height = '82px' align='justified'> 1.You have limited time to answer each question and your score will be shown at the end of the test. Good Luck!</div></body></html>",
        "Instructions",
        JOptionPane.INFORMATION_MESSAGE);
     }
 }

public interface Question {

    public String getPrompt();

    public void setButtonGroup(ButtonGroup buttonGroup);

    public ButtonGroup getButtonGroup();

    public String getCorrectAnswer();

    public String[] getOptions();

    public String getUserResponse();

    public void setUserResponse(String response);

    public boolean isCorrect();
}

public class ChoiceQuestion implements Question {

    private final String prompt;
    private final String correctAnswer;
    private final String[] options;
    private ButtonGroup buttonGroup;

    private String userResponse;

    public ChoiceQuestion(String prompt, String correctAnswer, String... options) {
        this.prompt = prompt;
        this.correctAnswer = correctAnswer;
        this.options = options;
    }

    @Override
    public void setButtonGroup(ButtonGroup buttonGroup) {
        this.buttonGroup = buttonGroup;
    }

    @Override
    public ButtonGroup getButtonGroup() {
        return this.buttonGroup;
    }

    @Override
    public String getPrompt() {
        return prompt;
    }

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

    @Override
    public String[] getOptions() {
        return options;
    }

    @Override
    public String getUserResponse() {
        return userResponse;
    }

    @Override
    public void setUserResponse(String response) {
        userResponse = response;
    }

    @Override
    public boolean isCorrect() {
        return getCorrectAnswer().equals(getUserResponse());
    }
}

public class QuestionPane extends JPanel {

    private Question question;

    private ButtonGroup buttonGroup = null;

    public QuestionPane(Question question) {
        this.question = question;

        setLayout(new BorderLayout());

        JLabel prompt = new JLabel("<html><b>" + question.getPrompt() + "</b></html>");
        prompt.setHorizontalAlignment(JLabel.LEFT);

        add(prompt, BorderLayout.NORTH);

        JPanel guesses = new JPanel(new GridBagLayout());
        guesses.setBorder(new EmptyBorder(10,10,10,10));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.weightx = 1;
        gbc.anchor = GridBagConstraints.WEST;

        List<String> options = new ArrayList<>(Arrays.asList(question.getOptions()));
        //options.add(question.getCorrectAnswer());
        Collections.sort(options);

        ButtonGroup bg = new ButtonGroup();
        for (String option : options) {
            JRadioButton btn = new JRadioButton(option);
            btn.setName(option);
            bg.add(btn);

            guesses.add(btn, gbc);
        }
        this.buttonGroup = bg;

        add(guesses);
    }

    public ButtonGroup getButtonGroup() {
        return buttonGroup;
    }

    public Question getQuestion() {
        return question;
    }

    public class ActionHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            getQuestion().setUserResponse(e.getActionCommand());
        }

    }

}

Hope it helps

Jorge
  • 1,136
  • 9
  • 15
  • So, this is just basically [this](http://stackoverflow.com/questions/30925564/why-is-my-jlabel-not-showing-up/30926625#30926625) – MadProgrammer Mar 31 '16 at 18:36