在多个 FXML 之间交互

Interact between several FXMLs

我正在尝试使用 javaFX 和 FXML 文件编写我的第一个应用程序,但我无法访问 FXML 的变量。

我可以从第一个场景(第一个 FXML)启动程序。有一个我可以与之交互的按钮,第一个场景隐藏,第二个场景出现。在那个场景中,用户必须在文本字段中插入一个值。通过在另一个按钮上确认此输入,我可以将其保存到变量中。 单击此按钮可隐藏第二个场景并再次打开第一个场景。现在我想将第一个场景中的标签值设置为我保存用户输入的变量值。但这会引发错误消息。 似乎此标签值不可访问,即使此标签是当前加载的 FXML 的一部分,但我能够获得第二个 FXML(用户交互字段)的标签值,该值不再可见。

谁能帮帮我,如何让第一个FXML的这个Label可读可改? 我的代码很长,但我懒得给你最重要的部分:

@FXML
private Label RollsMax;
@FXML
private TextField roll_input;
@FXML
private String amountRolls;
... // several more declarations
@FXML
void btn_confirmInput_onClick(ActionEvent event){ //btn_confirmInput is part of scene2.fxml
   event.consume();
   amountRolls=roll_input.getText();
   System.out.println(amountRolls); // here I get the result of the user's input
   try{
      root=FXMLLoader.load(getClass().getResource("project/scene1.fxml"));
      stage=(Stage)((Node)event.getSource()).getScene().getWindow();
      scene=new Scene(root);
      stage.setScene(scene);
      stage.show();
   } //end try
   catch (IOException e){
      e.printStackTrace();
   } //end catch
   RollsMax.setText(amountRolls); // THIS LINE IS NOT WORKING AS RollsMax SEEMS NOT AVAILABLE, EVEN IF IT IS PART OF SCENE1.fxml
} // end btn_confirmInput_onClick()

有什么想法吗?我得到的错误是 'java.lang.RuntimeException: java.lang.reflect.InvocationtargetException' 以及 'java.lang.NullPointerException'.

非常感谢! 编码器

为每个 FXML 使用控制器 class。然后你应该能够使用 public 方法在它们之间进行交互。

特别是当你只隐藏第一个场景时,你应该能够从一个场景写到另一个场景。

或者:在启动第二个场景时创建一个参数,将第一个场景的实例引入其中。比您应该能够在第一个场景实例上使用所需的方法。

喜欢

代码场景一

@FXML
private void startSceneTwoButton(){
    new SceneTwo(this);
}

代码场景二

FirstScene scene;

public SecondScene(FirstScene scene){
    this.scene = scene;
    //some code
}

@FXML
private void button(){
    scene.enterValue(value);
}

为了在场景之间共享数据,我们将引入一个 Model class 来保存共享信息:

public class Model {

    private SimpleStringProperty valueProperty = new SimpleStringProperty("N/A");

    public SimpleStringProperty getValueProperty() {
        return valueProperty;
    }
}

以及两个场景的控制器(实际上是两个场景的两个根的控制器)要实现的接口。
接口增加了向controller中注入aModel的功能:

public interface Controller {
    void setModel(Model model);
} 

sceneOne.fxml 带有切换场景的按钮和显示用户输入的标签:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" 
 prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/16" 
 xmlns:fx="http://javafx.com/fxml/1" fx:controller="SceneOneController">
   <children>
      <Label layoutX="159.0" layoutY="40.0" text="Scene 1">
         <font>
            <Font size="24.0" />
         </font>
      </Label>
      <Button layoutX="264.0" layoutY="246.0" mnemonicParsing="false" onAction="#changeScene" prefHeight="26.0" prefWidth="102.0" text="Get Input" />
      <Label fx:id="inputValue" layoutX="187.0" layoutY="142.0" text="Label" />
   </children>
</AnchorPane>

及其实现Controller接口的控制器:

public class SceneOneController implements Controller {

    @FXML Label inputValue;
    private Model model;

    public void changeScene(ActionEvent e) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("sceneTwo.fxml"));
            Parent root = loader.load();
            Controller controller = loader.getController(); //get a reference to sceneTwo controller
            controller.setModel(model);
             Stage stage = (Stage)((Node)e.getSource()).getScene().getWindow();
             stage.setScene(new Scene(root));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void setModel(Model model) {
        this.model = model;
        if(model != null){
            inputValue.textProperty().unbind();
            inputValue.textProperty().bind(model.valueProperty);
        }
    }
}

sceneTwo.fxml 带有切换场景的按钮和用于用户输入的 TextField:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane fx:id="main" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="SceneTwoController">
   <children>
      <Label layoutX="150.0" layoutY="41.0" text="Scene 2">
         <font>
            <Font size="24.0" />
         </font>
      </Label>
      <Button layoutX="264.0" layoutY="246.0" mnemonicParsing="false" onAction="#changeScene" prefHeight="26.0" prefWidth="102.0" text="Update" />
      <TextField fx:id="inputValue" layoutX="121.0" layoutY="138.0" prefHeight="25.0" prefWidth="162.0" />
   </children>
</AnchorPane>

及其控制器:

public class SceneTwoController implements Controller {

    @FXML TextField inputValue;
    private Model model;

    public void changeScene(ActionEvent e) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("sceneOne.fxml"));
            Parent root = loader.load();
            Controller controller = loader.getController();  //get a reference to sceneOne controller
            controller.setModel(model);
             Stage stage = (Stage)((Node)e.getSource()).getScene().getWindow();
             stage.setScene(new Scene(root));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void setModel(Model model) {
        this.model = model;
        if(model != null){
            inputValue.textProperty().unbind();
            model.valueProperty.bind(inputValue.textProperty());
        }
    }
}

最后是用于测试的应用程序:

public class SwitchSceneMVC extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{

        FXMLLoader loader = new FXMLLoader(getClass().getResource("sceneOne.fxml"));
        Parent root = loader.load();

        Model model = new Model();
        Controller controller = loader.getController();
        controller.setModel(model);

        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(null);
    }
}