Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
传递参数JavaFX-FXML_Javafx_Parameters_Dependency Injection_Parameter Passing_Fxml - Fatal编程技术网

传递参数JavaFX-FXML

传递参数JavaFX-FXML,javafx,parameters,dependency-injection,parameter-passing,fxml,Javafx,Parameters,Dependency Injection,Parameter Passing,Fxml,如何在javafx中将参数传递给辅助窗口?是否有与相应控制器通信的方法 例如: 用户从表视图中选择客户,并打开一个新窗口,显示客户信息 Stage newStage = new Stage(); try { AnchorPane page = (AnchorPane) FXMLLoader.load(HectorGestion.class.getResource(fxmlResource)); Scene scene = new Scene(page); newStag

如何在javafx中将参数传递给辅助窗口?是否有与相应控制器通信的方法

例如: 用户从
表视图
中选择客户,并打开一个新窗口,显示客户信息

Stage newStage = new Stage();
try 
{
    AnchorPane page = (AnchorPane) FXMLLoader.load(HectorGestion.class.getResource(fxmlResource));
    Scene scene = new Scene(page);
    newStage.setScene(scene);
    newStage.setTitle(windowTitle);
    newStage.setResizable(isResizable);
    if(showRightAway) 
    {
        newStage.show();
    }
}
newStage
将是新窗口。问题是,我找不到方法告诉控制器在哪里查找客户信息(通过将id作为参数传递)


有什么想法吗?

javafx.scene.Node类有一对方法 setUserData(对象) 及 对象getUserData()

您可以使用它将信息添加到节点

因此,您可以调用page.setUserData(info)

如果设置了信息,控制器可以进行检查。此外,如果需要,还可以使用ObjectProperty进行前向数据传输

请遵守此处的文档: 在短语“在第一个版本中,HandleButtoAction()用@FXML标记,以允许控制器文档中定义的标记调用它。在第二个示例中,对button字段进行注释,以允许加载程序设置其值。initialize()方法也进行了类似的注释。”


因此,您需要将控制器与节点关联,并将用户数据设置为该节点。

javafx.scene.node类有一对方法 setUserData(对象) 及 对象getUserData()

您可以使用它将信息添加到节点

因此,您可以调用page.setUserData(info)

如果设置了信息,控制器可以进行检查。此外,如果需要,还可以使用ObjectProperty进行前向数据传输

请遵守此处的文档: 在短语“在第一个版本中,HandleButtoAction()用@FXML标记,以允许控制器文档中定义的标记调用它。在第二个示例中,对button字段进行注释,以允许加载程序设置其值。initialize()方法也进行了类似的注释。”


因此,您需要将控制器与节点关联,并将用户数据设置到该节点。

推荐方法

这个答案列举了将参数传递给FXML控制器的不同机制

对于小型应用程序,我强烈建议直接将参数从调用者传递到控制器——它简单、直接,并且不需要额外的框架

对于更大、更复杂的应用程序,如果您希望在应用程序中使用或使用机制,则值得研究

将参数直接从调用者传递到控制器

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

FXMLLoader loader = new FXMLLoader(
    getClass().getResource(
        "customerDialog.fxml"
    )
);
loader.setController(dialogController);

Pane mainPane = loader.load();
通过从FXML加载程序实例检索控制器并调用控制器上的方法以使用所需的数据值对其进行初始化,将自定义数据传递给FXML控制器

类似于以下代码:

public Stage showCustomerDialog(Customer customer) {
  FXMLLoader loader = new FXMLLoader(
    getClass().getResource(
      "customerDialog.fxml"
    )
  );

  Stage stage = new Stage(StageStyle.DECORATED);
  stage.setScene(
    new Scene(loader.load())
  );

  CustomerDialogController controller = loader.getController();
  controller.initData(customer);

  stage.show();

  return stage;
}

...

class CustomerDialogController {
  @FXML private Label customerName;
  void initialize() {}
  void initData(Customer customer) {
    customerName.setText(customer.getName());
  }
}
新的FXMLLoader的构造如示例代码所示,即
newFXMLLoader(位置)
。该位置是一个URL,您可以通过以下方式从FXML资源生成该URL:

new FXMLLoader(getClass().getResource("sample.fxml"));
小心不要在FXMLLoader上使用静态加载函数,否则将无法从加载程序实例获取控制器

FXMLLoader实例本身对域对象一无所知。您不直接将特定于应用程序的域对象传递给FXMLLoader构造函数,而是:

  • 基于指定位置的fxml标记构造FXMLLoader
  • 从FXMLLoader实例获取控制器
  • 调用检索到的控制器上的方法,为控制器提供对域对象的引用
  • 这篇博客(由另一位作者撰写)提供了一个类似的备选方案

    在FXMLLoader上设置控制器

    CustomerDialogController dialogController = 
        new CustomerDialogController(param1, param2);
    
    FXMLLoader loader = new FXMLLoader(
        getClass().getResource(
            "customerDialog.fxml"
        )
    );
    loader.setController(dialogController);
    
    Pane mainPane = loader.load();
    
    您可以在代码中构造一个新的控制器,将您想要的任何参数从调用者传递到控制器构造函数中。构造控制器后,可以在调用
    load()
    instance方法之前在FXMLLoader实例上设置它

    要在加载程序上设置控制器(在JavaFX2.x中),还不能在fxml文件中定义
    fx:controller
    属性

    由于FXML中对
    fx:controller
    定义的限制,我个人更喜欢从FXMLLoader获取控制器,而不是将控制器设置到FXMLLoader中

    让控制器从外部静态方法检索参数

    谢尔盖的回答就是这种方法的例证

    使用依赖项注入

    FXMLLoader通过允许您在FXMLLoader上设置自定义控制器工厂来支持依赖项注入系统,如Guice、Spring或Java EE CDI。这提供了一个回调,您可以使用该回调创建控制器实例,该实例具有各自的依赖项注入系统注入的依赖值

    以下问题的答案中提供了使用Spring的JavaFX应用程序和控制器依赖项注入的示例:

    一个非常好的、干净的依赖项注入方法的例子是使用它的示例。afterburner.fx依赖JEE6执行依赖项注入

    使用事件总线

    最初的FXML规范创建者和实现者Greg Brown经常建议考虑使用事件总线(如Guava)在FXML实例化的控制器和其他应用程序逻辑之间进行通信

    EventBus是一个简单但功能强大的发布/订阅API,带有注释,允许POJO在JVM中的任何位置相互通信,而无需相互引用

    后续问答

    关于第一种方法,你们为什么要回到舞台上?该方法也可能是无效的,因为您已经给出了show()命令;就在返回阶段之前;。您如何通过返回舞台来计划使用

    它是问题的功能解决方案。从
    showCustomerDialog
    函数返回一个stage,以便对其进行引用
    public class ConcreteViewLoader extends GuiceFxmlLoader {
    
       @Inject
       public ConcreteViewLoader(Stage stage, Provider<MyController> provider) {
          super(stage, provider);
       }
    
       @Override
       public String getFileName() {
          return "my_view.fxml";
       }
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.BorderPane?>
    <?import javafx.scene.layout.VBox?>
    <VBox xmlns="http://javafx.com/javafx/null" xmlns:fx="http://javafx.com/fxml/1">
        <BorderPane>
            <center>
                <Label text="$labelText"/>
            </center>
        </BorderPane>
    </VBox>
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    import java.io.IOException;
    
    public class NamespaceParameterExampleApplication extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) throws IOException {
            final FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("namespace-parameter-example.fxml"));
    
            fxmlLoader.getNamespace()
                      .put("labelText", "External Text");
    
            final Parent root = fxmlLoader.load();
    
            primaryStage.setTitle("Namespace Parameter Example");
            primaryStage.setScene(new Scene(root, 400, 400));
            primaryStage.show();
        }
    }
    
    public class Context {
        private final static Context instance = new Context();
        public static Context getInstance() {
            return instance;
        }
    
        private Connection con;
        public void setConnection(Connection con)
        {
            this.con=con;
        }
        public Connection getConnection() {
            return con;
        }
    
        private TabRoughController tabRough;
        public void setTabRough(TabRoughController tabRough) {
            this.tabRough=tabRough;
        }
    
        public TabRoughController getTabRough() {
            return tabRough;
        }
    }
    
    Context.getInstance().setTabRough(this);
    
    TabRoughController cont=Context.getInstance().getTabRough();
    
    import javafx.application.Application;
    import javafx.stage.Stage;
    
    public class Main extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) {
    
            // Create the first controller, which loads Layout1.fxml within its own constructor
            Controller1 controller1 = new Controller1();
    
            // Show the new stage
            controller1.showStage();
    
        }
    }
    
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    import javafx.stage.Stage;
    
    import java.io.IOException;
    
    public class Controller1 {
    
        // Holds this controller's Stage
        private final Stage thisStage;
    
        // Define the nodes from the Layout1.fxml file. This allows them to be referenced within the controller
        @FXML
        private TextField txtToSecondController;
        @FXML
        private Button btnOpenLayout2;
        @FXML
        private Label lblFromController2;
    
        public Controller1() {
    
            // Create the new stage
            thisStage = new Stage();
    
            // Load the FXML file
            try {
                FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout1.fxml"));
    
                // Set this class as the controller
                loader.setController(this);
    
                // Load the scene
                thisStage.setScene(new Scene(loader.load()));
    
                // Setup the window/stage
                thisStage.setTitle("Passing Controllers Example - Layout1");
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Show the stage that was loaded in the constructor
         */
        public void showStage() {
            thisStage.showAndWait();
        }
    
        /**
         * The initialize() method allows you set setup your scene, adding actions, configuring nodes, etc.
         */
        @FXML
        private void initialize() {
    
            // Add an action for the "Open Layout2" button
            btnOpenLayout2.setOnAction(event -> openLayout2());
        }
    
        /**
         * Performs the action of loading and showing Layout2
         */
        private void openLayout2() {
    
            // Create the second controller, which loads its own FXML file. We pass a reference to this controller
            // using the keyword [this]; that allows the second controller to access the methods contained in here.
            Controller2 controller2 = new Controller2(this);
    
            // Show the new stage/window
            controller2.showStage();
    
        }
    
        /**
         * Returns the text entered into txtToSecondController. This allows other controllers/classes to view that data.
         */
        public String getEnteredText() {
            return txtToSecondController.getText();
        }
    
        /**
         * Allows other controllers to set the text of this layout's Label
         */
        public void setTextFromController2(String text) {
            lblFromController2.setText(text);
        }
    }
    
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    import javafx.stage.Stage;
    
    import java.io.IOException;
    
    public class Controller2 {
    
        // Holds this controller's Stage
        private Stage thisStage;
    
        // Will hold a reference to the first controller, allowing us to access the methods found there.
        private final Controller1 controller1;
    
        // Add references to the controls in Layout2.fxml
        @FXML
        private Label lblFromController1;
        @FXML
        private TextField txtToFirstController;
        @FXML
        private Button btnSetLayout1Text;
    
        public Controller2(Controller1 controller1) {
            // We received the first controller, now let's make it usable throughout this controller.
            this.controller1 = controller1;
    
            // Create the new stage
            thisStage = new Stage();
    
            // Load the FXML file
            try {
                FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout2.fxml"));
    
                // Set this class as the controller
                loader.setController(this);
    
                // Load the scene
                thisStage.setScene(new Scene(loader.load()));
    
                // Setup the window/stage
                thisStage.setTitle("Passing Controllers Example - Layout2");
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Show the stage that was loaded in the constructor
         */
        public void showStage() {
            thisStage.showAndWait();
        }
    
        @FXML
        private void initialize() {
    
            // Set the label to whatever the text entered on Layout1 is
            lblFromController1.setText(controller1.getEnteredText());
    
            // Set the action for the button
            btnSetLayout1Text.setOnAction(event -> setTextOnLayout1());
        }
    
        /**
         * Calls the "setTextFromController2()" method on the first controller to update its Label
         */
        private void setTextOnLayout1() {
            controller1.setTextFromController2(txtToFirstController.getText());
        }
    
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.AnchorPane?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.scene.layout.VBox?>
    <AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
        <VBox alignment="CENTER" spacing="10.0">
            <padding>
                <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
            </padding>
            <Label style="-fx-font-weight: bold;" text="This is Layout1!"/>
            <HBox alignment="CENTER_LEFT" spacing="10.0">
                <Label text="Enter Text:"/>
                <TextField fx:id="txtToSecondController"/>
                <Button fx:id="btnOpenLayout2" mnemonicParsing="false" text="Open Layout2"/>
            </HBox>
            <VBox alignment="CENTER">
                <Label text="Text From Controller2:"/>
                <Label fx:id="lblFromController2" text="Nothing Yet!"/>
            </VBox>
        </VBox>
    </AnchorPane>
    
    <?xml version="1.0" encoding="UTF-8"?>
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.AnchorPane?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.scene.layout.VBox?>
    <AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
        <VBox alignment="CENTER" spacing="10.0">
            <padding>
                <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
            </padding>
            <Label style="-fx-font-weight: bold;" text="Welcome to Layout 2!"/>
            <VBox alignment="CENTER">
                <Label text="Text From Controller1:"/>
                <Label fx:id="lblFromController1" text="Nothing Yet!"/>
            </VBox>
            <HBox alignment="CENTER_LEFT" spacing="10.0">
                <Label text="Enter Text:"/>
                <TextField fx:id="txtToFirstController"/>
                <Button fx:id="btnSetLayout1Text" mnemonicParsing="false" text="Set Text on Layout1"/>
            </HBox>
        </VBox>
    </AnchorPane>
    
    public class startController implements Initializable {
    
    @FXML Pane startPane,pageonePane;
    @FXML Button btnPageOne;
    @FXML TextField txtStartValue;
    public Stage stage;
    public static int intSETonStartController;
    String strSETonStartController;
    
    @FXML
    private void toPageOne() throws IOException{
    
        strSETonStartController = txtStartValue.getText().trim();
    
    
            // yourString != null && yourString.trim().length() > 0
            // int L = testText.length();
            // if(L == 0){
            // System.out.println("LENGTH IS "+L);
            // return;
            // }
            /* if (testText.matches("[1-2]") && !testText.matches("^\\s*$")) 
               Second Match is regex for White Space NOT TESTED !
            */
    
            String testText = txtStartValue.getText().trim();
            // NOTICE IF YOU REMOVE THE * CHARACTER FROM "[1-2]*"
            // NO NEED TO CHECK LENGTH it also permited 12 or 11 as valid entry 
            // =================================================================
            if (testText.matches("[1-2]")) {
                intSETonStartController = Integer.parseInt(strSETonStartController);
            }else{
                txtStartValue.setText("Enter 1 OR 2");
                return;
            }
    
            System.out.println("You Entered = "+intSETonStartController);
            stage = (Stage)startPane.getScene().getWindow();// pane you are ON
            pageonePane = FXMLLoader.load(getClass().getResource("pageone.fxml"));// pane you are GOING TO
            Scene scene = new Scene(pageonePane);// pane you are GOING TO
            stage.setScene(scene);
            stage.setTitle("Page One"); 
            stage.show();
            stage.sizeToScene();
            stage.centerOnScreen();  
    }
    
    private void doGET(){
        // Why this testing ?
        // strSENTbackFROMPageoneController is null because it is set on Pageone
        // =====================================================================
        txtStartValue.setText(strSENTbackFROMPageoneController);
        if(intSETonStartController == 1){
          txtStartValue.setText(str);  
        }
        System.out.println("== doGET WAS RUN ==");
        if(txtStartValue.getText() == null){
           txtStartValue.setText("");   
        }
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // This Method runs every time startController is LOADED
         doGET();
    }    
    }
    
    public class PageoneController implements Initializable {
    
    @FXML Pane startPane,pageonePane,pagetwoPane;
    @FXML Button btnOne,btnTwo;
    @FXML TextField txtPageOneValue;
    public static String strSENTbackFROMPageoneController;
    public Stage stage;
    
        @FXML
    private void onBTNONE() throws IOException{
    
            stage = (Stage)pageonePane.getScene().getWindow();// pane you are ON
            pagetwoPane = FXMLLoader.load(getClass().getResource("pagetwo.fxml"));// pane you are GOING TO
            Scene scene = new Scene(pagetwoPane);// pane you are GOING TO
            stage.setScene(scene);
            stage.setTitle("Page Two"); 
            stage.show();
            stage.sizeToScene();
            stage.centerOnScreen();
    }
    
    @FXML
    private void onBTNTWO() throws IOException{
        if(intSETonStartController == 2){
            Alert alert = new Alert(AlertType.CONFIRMATION);
            alert.setTitle("Alert");
            alert.setHeaderText("YES to change Text Sent Back");
            alert.setResizable(false);
            alert.setContentText("Select YES to send 'Alert YES Pressed' Text Back\n"
                    + "\nSelect CANCEL send no Text Back\r");// NOTE this is a Carriage return\r
            ButtonType buttonTypeYes = new ButtonType("YES");
            ButtonType buttonTypeCancel = new ButtonType("CANCEL", ButtonData.CANCEL_CLOSE);
    
            alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeCancel);
    
            Optional<ButtonType> result = alert.showAndWait();
            if (result.get() == buttonTypeYes){
                txtPageOneValue.setText("Alert YES Pressed");
            } else {
                System.out.println("canceled");
                txtPageOneValue.setText("");
                onBack();// Optional
            }
        }
    }
    
    @FXML
    private void onBack() throws IOException{
    
        strSENTbackFROMPageoneController = txtPageOneValue.getText();
        System.out.println("Text Returned = "+strSENTbackFROMPageoneController);
        stage = (Stage)pageonePane.getScene().getWindow();
        startPane = FXMLLoader.load(getClass().getResource("start.fxml")); 
        Scene scene = new Scene(startPane);
        stage.setScene(scene);
        stage.setTitle("Start Page"); 
        stage.show();
        stage.sizeToScene();
        stage.centerOnScreen(); 
    }
    
    private void doTEST(){
        String fromSTART = String.valueOf(intSETonStartController);
        txtPageOneValue.setText("SENT  "+fromSTART);
        if(intSETonStartController == 1){
           btnOne.setVisible(true);
           btnTwo.setVisible(false);
           System.out.println("INTEGER Value Entered = "+intSETonStartController);  
        }else{
           btnOne.setVisible(false);
           btnTwo.setVisible(true);
           System.out.println("INTEGER Value Entered = "+intSETonStartController); 
        }  
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        doTEST();
    }    
    
    }
    
    public class PagetwoController implements Initializable {
    
    @FXML Pane startPane,pagetwoPane;
    public Stage stage;
    public static String str;
    
    @FXML
    private void toStart() throws IOException{
    
        str = "You ON Page Two";
        stage = (Stage)pagetwoPane.getScene().getWindow();// pane you are ON
        startPane = FXMLLoader.load(getClass().getResource("start.fxml"));// pane you are GOING TO
        Scene scene = new Scene(startPane);// pane you are GOING TO
        stage.setScene(scene);
        stage.setTitle("Start Page"); 
        stage.show();
        stage.sizeToScene();
        stage.centerOnScreen();  
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
    
    }    
    
    }