我创建了以下对象,该对象负责在我的 win 应用程序中显示方向盘。
@DefaultProperty("children")
public class SteeringWheel extends Region {
@FXML
private Circle backgroundCircle;
@FXML
private Circle innerCircle;
@FXML
private Label mylabel;
public ObservableList<Node> getChildren() {
return super.getChildren();
}
public void setCirclesLocations() {
double centerPointX = getWidth() / 2;
double centerPointY = getHeight() / 2;
setCircleLocation(backgroundCircle, centerPointX, centerPointY);
setCircleLocation(innerCircle, centerPointX, centerPointY);
}
private void setCircleLocation(Circle c, double x, double y) {
c.setCenterX(x);
c.setCenterY(y);
}
我的 fxml 文件包含以下声明:
<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9.0.1" fx:controller="view.WindowController">
<center>
<VBox prefHeight="200" prefWidth="200" BorderPane.alignment="CENTER">
<children>
<SteeringWheel fx:id="steeringWheel">
<children>
<Label fx:id="mylabel" prefHeight="30.0" prefWidth="102.0" text="aileron" />
<Circle fx:id="innerCircle" fill="black" radius="40" />
<Circle fx:id="backgroundCircle" fill="darkgray" radius="100" />
</children>
</SteeringWheel>
</children>
</VBox>
</center>
.....
我试图将 xml 初始化映射到该对象,但它不起作用。在我的 main 中,我尝试运行 setCircleLocations 但出现空指针异常。
FXMLLoader fxl=new FXMLLoader();
try {
BorderPane root = fxl.load(getClass().getResource("Window.fxml").openStream());
WindowController wc=fxl.getController(); // View
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
wc.steeringWheel.setCirclesLocations();
} catch (IOException e) {
e.printStackTrace();
}
我的窗口 Controller :
public class WindowController {
@FXML
SteeringWheel steeringWheel;
}
此外,在 xml 文件中,我收到 SteeringWheel 子级的以下错误:未解析的 fx:id 引用
堆栈跟踪:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:473)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:372)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:973)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:198)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException
at view.WheelingSteer.setCircleLocation(WheelingSteer.java:36)
at view.WheelingSteer.setCirclesLocations(WheelingSteer.java:31)
at view.Main.start(Main.java:33)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:919)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(PlatformImpl.java:449)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
... 1 more
Exception running application view.Main
最佳答案
只有 Controller 注入(inject)了适当的字段。您的 SteeringWheel
类不是 Controller ,因此不会注入(inject)那些 @FXML
带注释的字段。不过,您打算注入(inject)这些字段的对象会放在 children
列表中,因此您可以在那里访问它们。但是,您似乎希望 SteeringWheel
成为其自己的组件,其中两个 Circle
和 Label
始终无论如何使用 SteeringWheel,都存在,因此尝试在单独的位置定义子级是没有意义的。
由于您要扩展Region
,您可能需要考虑使用 fx:root
:
import java.io.IOException;
import java.io.UncheckedIOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
public class SteeringWheel extends Pane {
@FXML private Label myLabel;
@FXML private Circle innerCircle;
@FXML private Circle backgroundCircle;
public SteeringWheel() {
FXMLLoader loader = new FXMLLoader(/* location */);
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
@FXML
private void initialize() {
// perform any initialization, if needed
}
@Override
public void layoutChildren() {
// Note: I didn't implement checking if the nodes are managed
// before laying them out. You may wish to add that
// behavior.
// The following will always keep the Circles in the center
// of the Pane. However, it does this by setting the layout[X|Y]
// properties rather than the center[X|Y] properties (as you're
// doing).
double x = snappedLeftInset();
double y = snappedTopInset();
double w = getWidth() - snappedRightInset() - x;
double h = getHeight() - snappedBottomInset() - y;
positionInArea(innerCircle, x, y, w, h, -1, HPos.CENTER, VPos.CENTER);
positionInArea(backgroundCircle, x, y, w, h, -1, HPos.CENTER, VPos.CENTER);
// Layout the Label in the top-left corner
layoutInArea(myLabel, x, y, w, h, -1, HPos.LEFT, VPos.TOP);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.shape.Circle?>
<fx:root type="javafx.scene.layout.Pane" xmlns="http://javafx.com/javafx/9.0.1"
xmlns:fx="http://javafx.com/fxml/1">
<Label fx:id="myLabel" text="Hello, World!"/>
<Circle fx:id="backgroundCircle" radius="30" fill="BLACK"/>
<Circle fx:id="innerCircle" radius="25" fill="FIREBRICK"/>
</fx:root>
注意:我扩展了 Pane
而不是 Region
。前者已经扩展了后者,并且已经进行了您所做的更改(即将 #getChildren()
方法公开并添加了 @DefaultProperty("children")
注释)。
注意:我覆盖了#layoutChildren()
,以便无论父级最终的尺寸如何,您的圆圈都保持在中心。但是,将它们简单地包装在其他布局中可能更容易,例如 StackPane
。
然后您只需在其他 FXML 文件中使用 SteeringWheel
即可:
<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9.0.1" fx:controller="view.WindowController">
<center>
<VBox prefHeight="200" prefWidth="200" BorderPane.alignment="CENTER">
<children>
<SteeringWheel fx:id="steeringWheel"/>
</children>
</VBox>
</center>
.....
关于java - 将嵌套对象从 fxml 映射到对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59768207/