JavaFX:在实例化控制器类时传递参数

时间:2015-06-13 01:29:37

标签: javafx java-8

我正在研究JavaFX应用程序。我的所有gui都是.fxml格式,并通过控制器类管理所有GUI组件。但是,在加载FXML加载器之前,我在 实例化控制器类 时遇到了困难。我无法从stackoverflow上的其他人那里找到一个很好的解决方案,因此这不是一个重复的问题。

我实例化控制器类的原因是我想 传递一些参数 ,以便这些参数将显示在GUI中。

我按以下方式加载FXML文件:

/*
 * for Work Order button
 */
@FXML
private void pressWorkOrder() throws Exception{ 
    WorkOrderController wo = new WorkOrderController("ashdkjhsahd");    //instantiating constructor     

    Parent parent = FXMLLoader.load(getClass().getResource("/fxml/WorkOrder.fxml"));        
    Scene scene = new Scene(parent);
    Stage stage = new Stage();
    stage.setScene(scene);
    stage.setTitle("Word Order");
    stage.setResizable(false);
    stage.show();
}

这是我的实际控制器类:

public class WorkOrderController implements Initializable{

     @FXML
     private Button summary;
     private String m,n;

     public WorkOrderController(String str) {
         // TODO Auto-generated constructor stub
         m = str;
     }  

     //for testing
     public void set(String str){
         m = str;
     }  

     @FXML
     public void check(){
         System.out.println("Output after constructor was initialized " + m);
     }

     @Override
     public void initialize(URL location, ResourceBundle resources) {
        // TODO Auto-generated method stub
     }
 }

我得到了这个例外:

at javafx.fxml.FXMLLoader.processStartElement(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at MainController.pressWorkOrder(MainController.java:78)
... 57 more
Caused by: java.lang.InstantiationException: WorkOrderController
at java.lang.Class.newInstance(Unknown Source)
at sun.reflect.misc.ReflectUtil.newInstance(Unknown Source)
... 71 more
Caused by: java.lang.NoSuchMethodException: WorkOrderController.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
... 73 more

2 个答案:

答案 0 :(得分:60)

为小型应用程序执行此操作的两种最简单方法是:

  1. 不要在fxml中指定fx:controller。通过向其传递数据来创建控制器实例,然后将其传递给FXMLLoader。

  2. 在fxml中指定fx:controller。从FXMLLoader获取控制器实例并将数据传递给控制器​​。

  3. 以下是上述两种类型的示例。每个示例都有3个组件:

    • FXML - FXML文件,doesn't have第一种类型的fx:controller声明,并将其用于第二种类型。
    • 控制器 - 第一种类型有constructor。第二种类型setter methods
    • Main - 用于加载FXML并将数据传递给控制器​​。对于第一种情况,它是sets the controller to FXMLLoader。排在第二位,fetches the controller from the FXMLLoader

    1。手动创建控制器实例

    FXML - 请勿指定fx:controller

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.FlowPane?>
    <?import javafx.scene.control.Label?>
    
    <FlowPane fx:id="root" xmlns:fx="http://javafx.com/fxml">
        <children>
            <Label fx:id="firstName" text="" />
            <Label fx:id="lastName" text="" />
        </children>
    </FlowPane>
    

    控制器 - 创建一个构造函数以接受默认值

    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Label;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    
    public class SampleController implements Initializable {
    
        private StringProperty firstNameString = new SimpleStringProperty();
        private StringProperty lastNameString = new SimpleStringProperty();
    
        /**
         * Accepts the firstName, lastName and stores them to specific instance variables
         * 
         * @param firstName
         * @param lastName
         */
        public SampleController(String firstName, String lastName) {
            firstNameString.set(firstName);
            lastNameString.set(lastName);
        }
    
        @FXML
        Label firstName;
    
        @FXML
        Label lastName;
    
        @Override
        public void initialize(URL location, ResourceBundle resources) {
            firstName.setText(firstNameString.get());
            lastName.setText(lastNameString.get());
        }
    }
    

    Main - 创建一个Controller实例,方法是将值传递给它,然后将其传递给FXMLLoader

    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.layout.FlowPane;
    import javafx.stage.Stage;
    
    public class Main extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Sample.fxml"));
    
            // Create a controller instance
            SampleController controller = new SampleController("itachi", "uchiha");
            // Set it in the FXMLLoader
            loader.setController(controller);
            FlowPane flowPane = loader.load();
            Scene scene = new Scene(flowPane, 200, 200);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    2。从FXMLLoader

    获取控制器实例

    FXML - 已指定fx:controller

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.FlowPane?>
    <?import javafx.scene.control.Label?>
    
    <!-- Controller Specified -->
    <FlowPane fx:id="root" xmlns:fx="http://javafx.com/fxml" fx:controller="SampleController">
        <children>
            <Label fx:id="firstName" text="" />
            <Label fx:id="lastName" text="" />
        </children>
    </FlowPane>
    

    控制器 - 具有接受输入的Setter方法

    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Label;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    
    public class SampleController implements Initializable {
    
        @FXML
        Label firstName;
    
        @FXML
        Label lastName;
    
        @Override
        public void initialize(URL location, ResourceBundle resources) {
    
        }
    
        /**
         * Accepts a String and sets it to the firstName Label
         *
         * @param firstNameString
         */
        public void setFirstName(String firstNameString) {
            firstName.setText(firstNameString);
        }
    
        /**
         * Accepts a String and sets it to the lastName Label
         *
         * @param lastNameString
         */
        public void setLastName(String lastNameString) {
            lastName.setText(lastNameString);
        }
    }
    

    Main - 调用load()后从FXMLLoader获取Controller实例,然后调用setter方法传递数据。

    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.layout.FlowPane;
    import javafx.stage.Stage;
    
    public class Main extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Sample.fxml"));
            FlowPane flowPane = loader.load();
            // Get the Controller from the FXMLLoader
            SampleController controller = loader.getController();
            // Set data in the controller
            controller.setFirstName("itachi");
            controller.setLastName("uchiha");
            Scene scene = new Scene(flowPane, 200, 200);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

答案 1 :(得分:3)

正如 a p 在评论中指出的,您可以使用控制器工厂,并且使用 lambda 函数更容易:

String data = "hsusanoo";

FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/WorkOrder.fxml"));

loader.setControllerFactory(WorkOrderController -> new WorkOrderController(data));

Parent root = loader.load();