[英]JavaFX - Wrapping FXML to Java Class Controller
I have a FXML file that has a TreeView control: 我有一个具有TreeView控件的FXML文件:
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test.MyControllerClass">
<TreeView fx:id="locationTreeView" layoutX="12.0" layoutY="158.0" prefHeight="193.0" prefWidth="471.0" />
Then my Java Class Controller needs to wrap with this TreeView and add TreeItem's dynamically. 然后我的Java类控制器需要用这个TreeView包装并动态添加TreeItem。 That's the problem, it isn't loading those TreeItem's.
这就是问题,它没有加载那些TreeItem。 That's the test code below, from my Controller:
这是我的控制器下面的测试代码:
public class MyControllerClass extends Application {
@FXML
private TreeView<String> locationTreeView;
@Override
public void start(Stage stage) throws Exception {
stage.initStyle(StageStyle.TRANSPARENT);
stage.getIcons().add(new Image(getClass().getResourceAsStream("myIcon.png")));
Parent root = FXMLLoader.load(getClass().getResource("myInterface.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
loadTreeItems();
stage.show();
}
// Just a simple example that still doesn't works
private void loadTreeItems() {
try {
TreeItem<String> root = new TreeItem<String>("Root Node");
root.setExpanded(true);
root.getChildren().addAll(
new TreeItem<String>("Item 1"),
new TreeItem<String>("Item 2"),
new TreeItem<String>("Item 3")
);
locationTreeView = new TreeView<String>(root);
} catch (Exception exc) {
System.out.println("Error: " + exc.getMessage());
}
}
public static void main(String[] args) {
launch(args);
}
}
Any ideas why its not working? 任何想法为什么它不工作?
There are a couple of reasons why your application doesn't work: 您的应用程序不起作用的原因有以下几种:
The way you have your application currently structured what will happen is: 您的应用程序当前结构化的方式将是:
MyControllerClass
on startup (and invoke it's start
method). MyControllerClass
的实例(并调用它的start
方法)。 FXMLLoader
will create another instance of MyControllerClass
each time the myInterface.fxml
file is loaded. myInterface.fxml
文件时 , FXMLLoader
都会创建另一个 MyControllerClass
实例 。 FXMLLoader
will create a new TreeView
instance and perform the FXML injection on the locationTreeView
member of the new MyControllerClass
instance it creates. FXMLLoader
将创建一个新的TreeView
实例,并在它创建的新 MyControllerClass
实例的locationTreeView
成员上执行FXML注入。 FXMLLoader
will try to invoke the initialize
method on the new MyControllerClass
(of which you have none). FXMLLoader
将尝试在新的MyControllerClass
上调用initialize
方法(其中没有)。 FXMLLoader
will not invoke the start
method on the new MyControllerClass
. FXMLLoader
不会在新的 MyControllerClass
上调用start
方法。 start
method invocation on your original MyControllerClass
will continue processing and create another new TreeView
instance which it will set the locationTreeView
member of the old MyControllerClass
instance to. MyControllerClass
上的原始start
方法调用将继续处理并创建另一个新的 TreeView
实例,它将旧 MyControllerClass
实例的locationTreeView
成员设置为。 I updated your code to make the modifications I suggested above and the code now works. 我更新了您的代码以进行上面建议的修改,现在代码可以正常工作。 The updated code is available .
更新的代码可用 。
A sample screenshot from the running code is: 运行代码的示例屏幕截图如下:
MyApplicationClass.java MyApplicationClass.java
import javafx.animation.*;
import javafx.application.Application;
import javafx.event.*;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.stage.*;
import javafx.util.Duration;
/** Sample application to demonstrate programming an FXML interface. */
public class MyApplicationClass extends Application {
@Override public void start(final Stage stage) throws Exception {
// load the scene fxml UI.
// grabs the UI scenegraph view from the loader.
// grabs the UI controller for the view from the loader.
final FXMLLoader loader = new FXMLLoader(getClass().getResource("myInterface.fxml"));
final Parent root = (Parent) loader.load();
final MyControllerClass controller = loader.<MyControllerClass>getController();
// continuously refresh the TreeItems.
// demonstrates using controller methods to manipulate the controlled UI.
final Timeline timeline = new Timeline(
new KeyFrame(
Duration.seconds(3),
new TreeLoadingEventHandler(controller)
)
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
// close the app if the user clicks on anywhere on the window.
// just provides a simple way to kill the demo app.
root.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent t) {
stage.hide();
}
});
// initialize the stage.
stage.setScene(new Scene(root));
stage.initStyle(StageStyle.TRANSPARENT);
stage.getIcons().add(new Image(getClass().getResourceAsStream("myIcon.png")));
stage.show();
}
/** small helper class for handling tree loading events. */
private class TreeLoadingEventHandler implements EventHandler<ActionEvent> {
private MyControllerClass controller;
private int idx = 0;
TreeLoadingEventHandler(MyControllerClass controller) {
this.controller = controller;
}
@Override public void handle(ActionEvent t) {
controller.loadTreeItems("Loaded " + idx, "Loaded " + (idx + 1), "Loaded " + (idx + 2));
idx += 3;
}
}
// main method is only for legacy support - java 8 won't call it for a javafx application.
public static void main(String[] args) { launch(args); }
}
MyControllerClass.java MyControllerClass.java
import javafx.fxml.FXML;
import javafx.scene.control.*;
/** Sample controller class. */
public class MyControllerClass {
// the FXML annotation tells the loader to inject this variable before invoking initialize.
@FXML private TreeView<String> locationTreeView;
// the initialize method is automatically invoked by the FXMLLoader - it's magic
public void initialize() {
loadTreeItems("initial 1", "initial 2", "initial 3");
}
// loads some strings into the tree in the application UI.
public void loadTreeItems(String... rootItems) {
TreeItem<String> root = new TreeItem<String>("Root Node");
root.setExpanded(true);
for (String itemString: rootItems) {
root.getChildren().add(new TreeItem<String>(itemString));
}
locationTreeView.setRoot(root);
}
}
myInterface.fxml myInterface.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns:fx="http://javafx.com/fxml" fx:controller="test.MyControllerClass">
<TreeView fx:id="locationTreeView" layoutX="0" layoutY="0" prefHeight="193.0" prefWidth="471.0" />
</AnchorPane>
In your loadTreeItems() function you are creating a new TreeView instance. 在loadTreeItems()函数中,您将创建一个新的TreeView实例。 This is replacing the one that is defined in your FXML file and attached to your scene with a new instance that is not part of the scene graph.
这将替换FXML文件中定义的并使用不属于场景图的新实例附加到场景的那个。
To add items to a TreeView that was created via the FXMLLoader you can use the setRoot() function. 要将项添加到通过FXMLLoader创建的TreeView,您可以使用setRoot()函数。
private void loadTreeItems() {
try {
TreeItem<String> root = new TreeItem<String>("Root Node");
root.setExpanded(true);
root.getChildren().addAll(
new TreeItem<String>("Item 1"),
new TreeItem<String>("Item 2"),
new TreeItem<String>("Item 3")
);
locationTreeView.setRoot(root);
} catch (Exception exc) {
System.out.println("Error: " + exc.getMessage());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.