【问题标题】:Interact between several FXMLs多个 FXML 之间的交互
【发布时间】:2022-01-19 11:38:04
【问题描述】:

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

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

谁能帮助我,如何使第一个 FXML 的这个标签可读和可更改? 我的代码很长,但我很厌烦给你最重要的部分:

@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'。

非常感谢! 结束编码器

【问题讨论】:

标签: java javafx fxml fxmlloader


【解决方案1】:

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

public class Model {

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

    public SimpleStringProperty getValueProperty() {
        return valueProperty;
    }
}

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

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);
    }
}

【讨论】:

    【解决方案2】:

    为每个 FXML 使用一个控制器类。然后您应该能够使用公共方法在它们之间进行交互。

    尤其是在隐藏第一个场景时,您应该能够从一个场景写入另一个场景。

    或者:在开始第二个场景时创建一个参数,将第一个场景的实例带到其中。比你应该能够在第一个场景实例上使用所需的方法。

    喜欢

    代码场景一

    @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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-12
      • 1970-01-01
      • 2022-12-01
      • 2017-06-23
      • 2020-03-15
      • 2018-06-03
      相关资源
      最近更新 更多