Подтвердить что ты не робот

JavaFX: передать параметры при создании класса контроллера

Я работаю над приложением JavaFX прямо сейчас. Весь мой gui находится в формате .fxml, а через класс контроллера управляет всеми компонентами GUI. Тем не менее, я испытываю трудности с созданием класса контроллера, прежде чем загружать загрузчик FXML. Я не смог найти хорошее решение для моего вопроса от других в stackoverflow, поэтому это не дублирующий вопрос.

Причина, по которой я создаю экземпляр класса контроллера, заключается в том, что я хочу передать некоторые параметры, чтобы эти параметры отображались в графическом интерфейсе.

Загружаю файл 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
4b9b3361

Ответ 1

Два самых простых способа сделать это для небольших приложений:

  • Не указывайте fx:controller в файле fxml. Создайте экземпляр контроллера, передав ему данные, а затем передайте его в FXMLLoader.

  • Укажите fx:controller в файле fxml. Извлеките экземпляр контроллера из FXMLLoader и передайте данные контроллеру.

Ниже приведены примеры обоих вышеупомянутых типов. Каждый из примеров имеет 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());
    }
}

Основной. Создайте экземпляр 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);
    }
}

Основной. Выбирает экземпляр Controller из FXMLLoader после вызова load(), а затем вызывает методы 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);
    }
}