JavaFX-在控制器类之间传递int值会产生错误的结果

时间:2019-04-10 04:18:41

标签: java javafx fxml

我正在做一个小测验游戏,但是当我尝试将一个控制器的值传递给另一个控制器时,答案总是与我期望的相反。基本上,选择了一个单选按钮,如果选择了正确的按钮,则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 returns NULL?

如果我尝试从我的Question1类中获取值的方式中存在错误,那是有道理的,但是我阅读的大多数其他帖子似乎也遵循了这种设计模式。拥有这是一个愚蠢的问题,但是无论如何我都无法解决。

我的returnValue()rb2.isSelected() == true时应返回1,但事实并非如此。我也尝试将score成员变量设为静态,但这没有帮助。关于这里可能出现的问题有什么想法或建议吗?先感谢您。

1 个答案:

答案 0 :(得分:1)

即使您使用static字段来存储结果,当您调用returnValue方法时,也会从场景中的控件中检索这些结果。

使用calculateScore方法第二次加载fxml会创建 新的场景版本 。在此新版本的场景中,无论用户在另一版本的场景中所做的输入如何,控件均处于初始状态。

我建议稍微重新设计应用程序:

  • 将问题的逻辑与“导航”问题的逻辑分开。
  • 保留控制器的参考以供以后评估。
  • 您可以通过与控制器实现接口来简化生活。

示例

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>