JavaFX - передача значений int между классами контроллера, что приводит к неверному результату - PullRequest
0 голосов
/ 10 апреля 2019

У меня есть небольшая игра-викторина, которую я делаю, однако, когда я пытаюсь передать значение от одного из моих контроллеров к другому, ответ всегда противоположен тому, что я ожидаю.Обычно выбирается переключатель, и если выбран правильный, метод returnValue() должен возвращать 1, иначе 0. Это говорит мне, выбрал ли пользователь правильный ответ или нет.Код для контроллера 1:

public class Question1
{
    @FXML
    private Label question1Lbl;
    @FXML
    private RadioButton rb1;
    @FXML
    private RadioButton rb2;
    @FXML
    private RadioButton rb3;

    private static int score;

    public void nextQuestion(ActionEvent actionEvent)
    {
        try
        {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("../gui/Question2.fxml"));
            Parent rootPane = loader.load();
            Stage primaryStage = new Stage();
            primaryStage.setScene(new Scene(rootPane));
            primaryStage.setResizable(false);
            primaryStage.setTitle("Frage 2");
            primaryStage.show();
            rb1.getScene().getWindow().hide();
        }
        catch (Exception e)
        {
            System.out.println("Error loading question 1" + e.toString());
            e.printStackTrace();
        }
    }
    //returns the points for this question. 1 for correct, 0 for incorrect
    public int returnValue()
    {

        if (!rb2.isSelected())
        {
            score = 0;
            return score;
        }
        score = 1;
        return score;
    }
}

Предполагается, что класс FinishScreen подсчитывает баллы, полученные по всем методам returnValue(), и отображает счет, но, независимо от того, что я пытаюсь, Question1класс всегда возвращает 0 независимо от того, была выбрана радиокнопка или нет!Я уже писал такой код, и он работал отлично, поэтому я очень запутался.У меня есть еще 4 класса, как это тоже.В любом случае, вот класс FinishScreen:

public class FinishScreen implements Initializable
{
    @FXML
    private Label resultLbl;

    private int totalScore;

    public void calculateScore() throws Exception
    {
        FXMLLoader loader1 = new FXMLLoader(getClass().getResource("../gui/Question1.fxml"));
        Parent root1 = loader1.load();
        Question1 q1 = loader1.getController();

        totalScore = q1.returnValue();
        System.out.println(totalScore);
        resultLbl.setText("Score: " + totalScore);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources)
    {
        try
        {
            calculateScore();
        }
        catch (Exception e)
        {
            System.out.println("Error in results " + e.toString());
        }

    }
}

Я использовал информацию из этого поста в качестве справки о том, как передавать значения из одного контроллера в другой: FXMLLoader getController возвращает NULL?

Если в том, как я пытаюсь получить значение из моего Question1 класса, возникает ошибка, которая имеет смысл, но большинство других постов, которые я прочитал, похоже, следуют этому шаблону разработки.Это глупая проблема, но я все равно не могу ее понять.

Мой returnValue() должен возвращать 1, когда rb2.isSelected() == true, но это не так.Я также пытался сделать статическую переменную-член score, но это не помогло.Любые идеи или предложения относительно того, что может быть проблемой здесь?Заранее спасибо.

1 Ответ

1 голос
/ 10 апреля 2019

Даже если вы используете поле static для хранения результатов, эти результаты извлекаются из элементов управления в сцене, когда вы вызываете метод returnValue.

Загрузка fxml во второй раз, как вы делаете это в методах calculateScore, создает новую версию сцены . В этой новой версии сцены элементы управления находятся в их начальных состояниях независимо от пользовательского ввода, выполненного в другой версии сцены.

Рекомендую немного изменить дизайн приложения:

  • Отделите логику вопроса от логики «навигации» по вопросам.
  • Сохраните ссылку на контроллер для последующей оценки.
  • Вы можете сделать вашу жизнь проще, внедрив интерфейс с вашими контроллерами.
* ** 1 022 тысяча двадцать-один * Пример
private int questionIndex = -1;

@Override
public void start(Stage primaryStage) throws Exception {
    StackPane questionContainer = new StackPane();
    questionContainer.setAlignment(Pos.TOP_LEFT);
    questionContainer.setPrefSize(300, 300);

    // create question list repeating our only question
    List<URL> questions = new ArrayList<>();
    URL url = getClass().getResource("/my/package/question1.fxml");
    for (int i = 0; i < 5; i++) {
        questions.add(url);
    }

    List<QuestionController> questionControllers = new ArrayList<>(questions.size());

    Button next = new Button("next");
    EventHandler<ActionEvent> handler = evt -> {
        if (questionIndex + 1 < questions.size()) {
            questionIndex++;

            // load next question & store controller for later evaluation
            FXMLLoader loader = new FXMLLoader(questions.get(questionIndex));
            try {
                questionContainer.getChildren().setAll(loader.<Node>load());
                questionControllers.add(loader.getController());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            // display results
            Alert alert = new Alert(AlertType.INFORMATION);
            alert.setContentText("You've answered "
                + questionControllers.stream().mapToInt(QuestionController::getScore).sum()
                + " / " + questionControllers.size()
                + " questions correctly.");
            alert.showAndWait();
            primaryStage.close();
        }
    };
    next.setOnAction(handler);

    // activate first question
    handler.handle(null);

    primaryStage.setScene(new Scene(new VBox(questionContainer, next)));
    primaryStage.show();
}
public interface QuestionController {
    int getScore();
}
public class Question1Controller implements QuestionController {

    private static final Random random = new Random();

    private int correctAnswer;

    @FXML
    private List<RadioButton> buttons;

    @FXML
    private void initialize() {

        // randomly assign correct answer
        correctAnswer = random.nextInt(buttons.size());

        for (RadioButton btn : buttons) {
            btn.setText("incorrect");
        }

        buttons.get(correctAnswer).setText("correct");
    }

    @Override
    public int getScore() {
        return buttons.get(correctAnswer).isSelected() ? 1 : 0;
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<?import java.util.ArrayList?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.RadioButton?>

<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="my.package.Question1Controller">
    <children>
        <RadioButton fx:id="b1" />
        <RadioButton fx:id="b2" />
        <RadioButton fx:id="b3" />
        <fx:define>
            <ArrayList fx:id="buttons">
                <fx:reference source="b1"/>
                <fx:reference source="b2"/>
                <fx:reference source="b3"/>
            </ArrayList>
        </fx:define>
    </children>
</VBox>
...