1

I have to set a "quiz" in Java, using JPanel and JRadioButton.

My code starts with reading a text from a file and putting it on a panel, with radio buttons, button groups and panel. So far, so good.

However my problem starts when I have to collect the data from the user and compare it with the right answers.

I have class Questions, Answers and Read (besides main and display on panel).

My way of thinking was that when the user clicks the submit button the code stars to check to quiz. However, nothing happens when I click it on the window opened.

I collect the data to ArrayList for comparison.

The checkQuiz method is supposed to be called after the user submits the quiz. It compares the radio button selected text with an answer. The program is supposed to be "running" until the user clicks the "submit" button, however I believe it does not happen.

I tried to use ActionListener in the code but I couldn't compare the user's choice with the data I am using.

I am sorry for the lots of code. I tried to post a mcve question. As far as I know the code is compilable, but I couldn't neglect any more lines.

Thank you for your help, and the code is below. App

Class DisplayOnPanel creates a Frame for the subclass to use:

import javax.swing.JFrame;

public class DisplayOnPanel extends JFrame {
    JFrame frame = new JFrame();
    public DisplayOnPanel(){
        frame.setSize(500,500);
    }
}

Class Main:

public class Main {
public static void main (String[]args){
      new Read();
    }
}

Clsas Questions:

public class Question {
private String _question;
private String _option1;
private String _option2;
private String _option3;
private String _option4;
private int _qIndex=0;
public Question(String question, String option1, String option2, String option3,
                String option4){
    this._question = question;
    this._option1 = option1;
    this._option2 = option2;
    this._option3 = option3;
    this._option4 = option4;


}
public void set_qIndex(int index) {
    this._qIndex = index;
}

Class Read - Reads from a file and then displays the results on the panel. It also fills ArrayLists with Answers, Questions, ButtonGroups and JPanels.

import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class Read extends DisplayOnPanel {


protected ArrayList<Question> Questions = new ArrayList<>();
protected ArrayList<ButtonGroup> BG = new ArrayList<>();
protected ArrayList<JPanel> JP = new ArrayList<>();
protected ArrayList<Answer> Answers = new ArrayList<>();
protected int qNumber = 0, finalscore = 0;
private JLabel lblScore;
private JToggleButton Submit = new JToggleButton();
//constructor

public Read() {
    super();
    //a "label" in the file will indicate the final score
    final int NUMBER_OF_LABELS_ADDED_TO_FRAME = 1;
    int number_of_lines_in_the_file, final_score = 0;
    try {
        number_of_lines_in_the_file = read(Questions);
        addButtonsToFrame(Questions, number_of_lines_in_the_file +
                NUMBER_OF_LABELS_ADDED_TO_FRAME, BG, JP);
        Submit.setText("Submit Quiz"); //create a submit button
        JPanel SubmitPanel = new JPanel();
        SubmitPanel.setVisible(true);
        this.add(SubmitPanel);
        SubmitPanel.add(Submit);

Submit.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    for (int i = 0; i < BG.size(); i++) {
                        //handle cases of the user didn't complete the test
                        if (BG.get(i).getSelection()==null) {
                            JOptionPane.showMessageDialog(frame, "Exam not finished - Restart.");
                            i=BG.size()-1; //finish the loop
                            frame.setVisible(false);
                            dispose();
                            new Read();
                        }
                    }
                    checkQuiz(BG, Answers, ONE_QUESTION_GRADE); //check quiz
                    Submit.setEnabled(false); //can't redo quiz //
                    // unless "Restart" pressed


                }
            });            
//adding final score label
        lblScore = new JLabel("Your Final Score: " + finalscore);
        add(lblScore);
        pack();
        this.setVisible(true);
        while (!Submit.isSelected()) {
            if (Submit.isSelected()) {
                checkQuiz(BG, Answers);
            }
        }
    } catch (FileNotFoundException e) {
        System.out.println("couldn't open file");
    }
}
//the method reads from the file


//returns the number of lines (quesiton) in the file

public int read(ArrayList<Question> Questions) throws FileNotFoundException {
    int number_of_lines = 0;
    try {
        File f = new File("C:\\Users\\Assaf\\Desktop\\exam.txt");
        Scanner input = new Scanner(f);
        //read from file direcly into the constructor
        while (input.hasNext()) {
            Question q = new Question((input.nextLine())
                    , (input.nextLine()),
                    (input.nextLine()),
                    (input.nextLine()),
                    (input.nextLine()));
            //adding the question and the answers to an array
            Questions.add(q);
            number_of_lines++;
            q.set_qIndex(number_of_lines);
            Answers.add(new Answer(q));

        }
        input.close();
    } catch (FileNotFoundException nf) {
        System.out.println("couldn't open file");
    }
    //return number of lines in the file
    return number_of_lines;
}
public void addButtonsToFrame(ArrayList<Question> q, int number_of_lines,
                              ArrayList<ButtonGroup> BG, ArrayList<JPanel> JP) {
    int j = 0;
    for (int i = 0; i < q.size(); i++) {
        qNumber = i;
        BG.add(new ButtonGroup());
        JP.add(new JPanel());
        JP.get(i).setSize(499, 400);
        //creating buttons
JRadioButton option1 = new JRadioButton(q.get(i).get_option1());
option1.setActionCommand(q.get(i).get_option1());
JRadioButton option2 = new JRadioButton(q.get(i).get_option2());
option2.setActionCommand(q.get(i).get_option2());
JRadioButton option3 = new JRadioButton(q.get(i).get_option3());
option3.setActionCommand(q.get(i).get_option3());
JRadioButton option4 = new JRadioButton(q.get(i).get_option4());
option4.setActionCommand(q.get(i).get_option4());
        //adding to group buttons
        BG.get(j).add(option1);
        BG.get(j).add(option2);
        BG.get(j).add(option3);
        BG.get(j).add(option4);
        //adding the buttons to the panel
        JP.get(j).add(option1);
        JP.get(j).add(option2);
        JP.get(j).add(option3);
        JP.get(j).add(option4);
        //setting layout that matches our goal
        this.setLayout(new GridLayout(number_of_lines + 1, 1));
        //set title and border for each question
        JP.get(i).setBorder(BorderFactory.createTitledBorder(
                BorderFactory.createEtchedBorder(), "question number " + qNumber + ": " + q.get(i).get_question()));
        //adding the panel to the frame
        this.add(JP.get(j));
        //BG.get(i).getSelection()
        JP.get(j).setVisible(true);
        j++;
    }
}
public void checkQuiz(ArrayList<ButtonGroup> BG, ArrayList<Answer> A) {
    ArrayList<String> Selections = new ArrayList<>();
    int CORRECT_ANSWER = 0;
    for (int i = 0; i < BG.size(); i++) {
        if (BG.get(i).getSelection().getActionCommand()
                .compareTo(A.get(i).get_answer()) == CORRECT_ANSWER) {
            finalscore = finalscore + 10;
        }
    }

}

Class Answer

public class Answer {
private String _question;
private String _answer;
private int _qIndex=0;

public Answer (Question q){
    this._answer = q.get_option1();
    this._question=q.get_question();
    this._qIndex=q.get_qIndex();

}

Edit - posted my working code.

Assaf
  • 1,112
  • 4
  • 14
  • 35
  • I don't find any `EventListener` in your code. Also the `frame` object you created in `DisplayOnPanel` is of no use as it is not utilized anywhere – Praveen Nov 29 '17 at 10:38
  • The problem with an EventListener here is that I get a nullPointerException since I try to make a comparison with CheckQuiz method. How Can I use it? Thank you! – Assaf Nov 29 '17 at 10:42
  • I tried to work with an EvenListener - and Found out I couldn't invoke another method which works with the arrays - getting null exceptions all the time. – Assaf Nov 29 '17 at 10:43
  • `"The program is supposed to be "running" until the user clicks the "submit" button, however I believe it does not happen."` That's NOT how swing works. You don't need a loop, and that would freeze your gui. Just use an `ActionListener` on your submit button, and check which radiobuttons are selected by using `isSelected ()` on your radiobuttons when an event (click on the button, or key pressed on it) occurs. – Ansharja Nov 29 '17 at 11:34
  • Thank you @Ansharja, That's a great idea - but I get a null exception when i try to do that. the BG and the rest of the arrays are null when I do that for some reason. – Assaf Nov 29 '17 at 11:40
  • Applications in a GUI work event driven, small parts responding to events, like a button press. Not sequential in time. Maybe first inspect some small demo applications. – Joop Eggen Nov 29 '17 at 11:53
  • Try to edit your code in order to create a real [mcve] where you use an `ActionListener`. The suggested way works, you are doing something wrong. – Ansharja Nov 29 '17 at 11:53

1 Answers1

1

i) You need to set action command before getting it,

JRadioButton option1 = new JRadioButton(q.get(i).get_option1());
option1.setActionCommand(q.get(i).get_option1());
JRadioButton option2 = new JRadioButton(q.get(i).get_option2());
option2.setActionCommand(q.get(i).get_option2());
JRadioButton option3 = new JRadioButton(q.get(i).get_option3());
option3.setActionCommand(q.get(i).get_option3());
JRadioButton option4 = new JRadioButton(q.get(i).get_option4());
option4.setActionCommand(q.get(i).get_option4());

ii) You haven't set the final score in your label in the end of checkQuiz method,
lblScore.setText("Your Final Score: " + finalscore);

iii) It is not advisable to use a while loop. Also checkQuiz method will not be invoked most of the time with the current logic you use. Hence use an ActionListener interface instead of a while,

Submit.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent arg0) {
         checkQuiz(BG, Answers);
    }
});
Praveen
  • 1,791
  • 3
  • 20
  • 33
  • Thank you!!! What does "setActionCommand" do what a "Regular" ActionListener doesn't? – Assaf Nov 29 '17 at 11:53
  • 1
    `setActionCommand` sets the action command in `String` format which helps you in identifying the action to perform during and `ActionEvent` in the `ActionListener` – Praveen Nov 29 '17 at 13:44