我正在研究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
答案 0 :(得分:60)
为小型应用程序执行此操作的两种最简单方法是:
不要在fxml中指定fx:controller
。通过向其传递数据来创建控制器实例,然后将其传递给FXMLLoader。
在fxml中指定fx:controller
。从FXMLLoader获取控制器实例并将数据传递给控制器。
以下是上述两种类型的示例。每个示例都有3个组件:
doesn't have
第一种类型的fx:controller
声明,并将其用于第二种类型。constructor
。第二种类型setter methods
。sets the controller to FXMLLoader
。排在第二位,fetches the controller from the FXMLLoader
。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);
}
}
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();