0

I have 3 Controller classes, each of those are set for difference scene.fxml files.

When the application runs it asks for student name and id, which is being done on first Controller class. Once the user passes all quiz questions, the program counts correct and wrong answers which is being done in Controller 2 class. And I have the third Controller 3 class where I am trying make a StudentRecord object and pass name and id from Controller class and correct and wrong answers from Controller 2 class.

Code successfully takes the input for name and id and runs the method, same thing with correct and wrong answers. But the problem is that the results output screen shows correct and wrong answers but not the name and id.

Is there a way to pass all values into Controller 3 object so it will display everything properly ?

Controller`


package com.example.vivoquiz;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;

public class Controller {

    private Stage stage;
    private Scene scene;
    private Parent root;

    public Backend backend;

    @FXML
    private Label fx_label;

    @FXML
    private TextField fx_studentName;

    @FXML
    private TextField fx_studentId;

    @FXML
    private Label promptMessage;

    /**
     * Controller for scene1.fxml
     * @throws FileNotFoundException for file search
     * @author David Arzumanyan
     */
    public Controller() throws FileNotFoundException {
        this.backend = new Backend("src/main/resources/com/example/vivoquiz/QuizFile");
        this.backend.parse_questions();

    }

    @FXML
    private void initialize() {
        int amountOfQuestions = this.backend.amount_of_questions();
        fx_label.setText(amountOfQuestions + " questions");
    }


    /**
     * When the start button is being clicked`
     * Method first checks received inputs from user for name and id
     * if input meets expectations as for name (int,char) and for id (int) only,
     * the condition will be set true, and will be redirected to the next page.
     * @param event defines the event
     * @throws IOException for FXMLLoader
     * @author David Arzumanyan
     */
    @FXML
    public void onStartTestButton(ActionEvent event) throws IOException {
        // Declaring a condition for next page
        boolean condition = false;

        // Student name and ID check
        // Name can contain string + char + int
        // ID must contain digits only
        try{
            int nameCheck = Integer.parseInt(this.fx_studentName.getText());
            this.promptMessage.setVisible(true);
        }
        catch (NumberFormatException err){
            if (this.fx_studentName.getText().length() <= 2){
                this.promptMessage.setVisible(true);
            }
            else{
                //this.student.setName(fx_studentName.getText());
                this.promptMessage.setVisible(false);
                condition = true;
            }
        }

        try{
            int studentId = Integer.parseInt(this.fx_studentId.getText());
            //this.student.setId(studentId);
            if (condition){
                this.promptMessage.setVisible(false);
            }
        }
        catch (NumberFormatException err){
            this.promptMessage.setVisible(true);
            condition = false;
        }

        // If the condition is true, moving to next page
        if (condition){

            FXMLLoader loader1 = new FXMLLoader(Objects.requireNonNull(getClass().getResource("scene3.fxml")));
            loader1.load();

            Controller3 controller3 = loader1.getController();
            controller3.setStudentNameAndID(this.fx_studentName.getText(), Integer.parseInt(this.fx_studentId.getText()));

            this.root = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("scene2.fxml")));
            this.stage = (Stage)((Node) event.getSource()).getScene().getWindow();
            this.scene = new Scene(root);

            String css = Objects.requireNonNull(getClass().getResource("style.css")).toExternalForm();
            this.scene.getStylesheets().add(css);

            this.stage.setScene(this.scene);
            this.stage.show();
        }

    }

}

Controller 2`


package com.example.vivoquiz;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.stage.Stage;

import java.io.FileNotFoundException;
import java.io.IOException;

public class Controller2 {

    private int counter;

    private final Backend backend;

    private int correctAnswers;

    private int wrongAnswers;

    @FXML
    private Label myQuestion;

    @FXML
    private RadioButton fx_option1, fx_option2, fx_option3, fx_option4;

    private Stage stage;
    private Scene scene;
    private Parent root;

    /**
     * Default/Main constructor
     * @throws FileNotFoundException throws if file not found.
     * @author David Arzumanyan
     */
    public Controller2() throws FileNotFoundException {
        // Initializing the backend, providing path and parsing all questions.
        this.backend = new Backend("src/main/resources/com/example/vivoquiz/QuizFile");
        backend.parse_questions();

        this.counter = 0;
        this.correctAnswers = 0;
        this.wrongAnswers = 0;
    }

    /**
     * initialize() method comes from the interface,
     * and is used by the JavaFX runtime to initialize the controller when it is created in the call to FXMLLoader. load()
     * from the preceding Application class.
     * <p>
     * In current case, we set texts for all labels of JavaFX,
     * so when the window is opened we have all fields ready.
     * @author David Arzumanyan
     */
    @FXML
    private void initialize(){
        this.myQuestion.setText(this.backend.getQuestions_list().get(this.counter).getQuestion());
        this.fx_option1.setText(this.backend.getQuestions_list().get(this.counter).getOption1());
        this.fx_option2.setText(this.backend.getQuestions_list().get(this.counter).getOption2());
        this.fx_option3.setText(this.backend.getQuestions_list().get(this.counter).getOption3());
        this.fx_option4.setText(this.backend.getQuestions_list().get(this.counter).getOption4());
    }

    /**
     * onSubmit() method is set on Submit FXML button.
     * When submitting, method checks which radio button is checked.
     * After checking it, compares the radio button answer with the actual question answer.
     * @author David Arzumanyan
     */
    @FXML
    public void onSubmit() throws IOException {

        if (fx_option1.isSelected()) {
            String userChoice = fx_option1.getText();

            String answer = this.backend.getQuestions_list().get(this.counter).getCorrect_answer();

            if (userChoice.equals(answer)){
                this.correctAnswers += 1;
            }
            else{
                this.wrongAnswers += 1;
            }
        }

        else if (fx_option2.isSelected()) {
            String userChoice = fx_option2.getText();

            String answer = this.backend.getQuestions_list().get(this.counter).getCorrect_answer();

            if (userChoice.equals(answer)){
                this.correctAnswers += 1;
            }
            else{
                this.wrongAnswers += 1;
            }
        }

        else if (fx_option3.isSelected()) {
            String userChoice = fx_option3.getText();

            String answer = this.backend.getQuestions_list().get(this.counter).getCorrect_answer();

            if (userChoice.equals(answer)){
                this.correctAnswers += 1;
            }
            else{
                this.wrongAnswers += 1;
            }
        }

        else if (fx_option4.isSelected()) {
            String userChoice = fx_option4.getText();

            String answer = this.backend.getQuestions_list().get(this.counter).getCorrect_answer();

            if (userChoice.equals(answer)){
                this.correctAnswers += 1;
            }
            else{
                this.wrongAnswers += 1;
            }
        }

        int lastQuestionIndex = this.backend.getQuestions_list().size();
        if (this.myQuestion.getText().equals(this.backend.getQuestions_list().get(lastQuestionIndex - 1).getQuestion())){

            FXMLLoader loader = new FXMLLoader(getClass().getResource("scene3.fxml"));
            this.root = loader.load();

            Controller3 controller3 = loader.getController();
            controller3.labelInitializers(this.correctAnswers, this.wrongAnswers);

            this.stage = (Stage) this.myQuestion.getScene().getWindow();
            this.scene = new Scene(root);
            this.stage.setScene(this.scene);
            this.stage.show();
        }

        else{
            this.counter += 1;
            changeQuestionObject();
        }


    }

    /**
     * Method changes all FXML fields texts with next
     * questions infos. Such as option1, option2, option3, option4 and answer.
     * @author David Arzumanyan
     */
    public void changeQuestionObject() throws IOException {

        String nextQuestion = this.backend.getQuestions_list().get(this.counter).getQuestion();
        this.myQuestion.setText(nextQuestion);

        String nextOption1 = this.backend.getQuestions_list().get(this.counter).getOption1();
        this.fx_option1.setText(nextOption1);

        String nextOption2 = this.backend.getQuestions_list().get(this.counter).getOption2();
        this.fx_option2.setText(nextOption2);

        String nextOption3 = this.backend.getQuestions_list().get(this.counter).getOption3();
        this.fx_option3.setText(nextOption3);

        String nextOption4 = this.backend.getQuestions_list().get(this.counter).getOption4();
        this.fx_option4.setText(nextOption4);

    }


}


Controller 3`

package com.example.vivoquiz;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class Controller3 {

    private StudentRecord student;
    @FXML
    private Label fx_studentName;

    @FXML
    private Label fx_studentID;

    @FXML
    private Label fx_studentScore;

    @FXML
    private Label fx_correctAnswers;

    @FXML
    private Label fx_wrongAnswers;

    public Controller3(){
        this.student = new StudentRecord();
    }

    public void setStudentNameAndID(String name, int id){
        this.student.setName(name);
        this.student.setId(id);

        this.fx_studentName.setText("Student name : " + this.student.getName());
        this.fx_studentID.setText("Student ID: " + this.student.getId());
    }

    public void labelInitializers(int correctAnswers, int wrongAnswers){
        this.student.setCorrect_answers(correctAnswers);
        this.student.setWrong_answers(wrongAnswers);

        this.fx_studentScore.setText("Total score: " + ((student.getCorrect_answers() + student.getWrong_answers()) - student.getWrong_answers()));
        this.fx_correctAnswers.setText("Correct answers: " + student.getCorrect_answers());
        this.fx_wrongAnswers.setText("Wrong answers: " + student.getWrong_answers());

    }
}

David
  • 27
  • 5
  • 1
    In Controller 2 you are calling `labelInitializers` but never pass the values of student name and id. Also, I see student id and name exist only in controller 1 and you are passing it to controller 3 there but I suspect controller is recreated each time you create a new loader, so the value never persists. I am not sure what is the best practice, since I have never used JavaFX but you can try to pass student name and id from controller 1 to controller 2 and then to controller 3. Also, you can wrap these 2 variables in a class called StudentInfo so you pass only 1 reference instead of 2 values. – Turkhan Badalov Apr 16 '23 at 04:18
  • 1
    Awesome, I did pass name and id from Controller to Controller2 and only from Controller2 passed into Controller3. And it worked. I assume before it was setting the name and the id for Controller3, but the Controller2 was resetting already assigned name and id when it was assigning the correct and wrong answers. Thank you for your help. – David Apr 16 '23 at 04:52
  • 1
    Consider using a [MVC approach](https://stackoverflow.com/questions/32342864/applying-mvc-with-javafx). That will probably simplify a lot of your code. – James_D Apr 16 '23 at 16:12

0 Answers0