将嵌套对象从fxml映射到对象 [英] Mapping nested object from fxml to object

查看:72
本文介绍了将嵌套对象从fxml映射到对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了以下对象,该对象应负责在我的Win应用程序中显示方向盘.

I created the following object which should be responsible for displaying a steeringwheel in my win app.

@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文件包含以下内容:

and my fxml file contains the following decleration :

<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初始化映射到该对象,但是它不起作用.在我的主机中,我试图运行setCircleLocations,但我遇到了nullpointer异常.

I'm trying to map the xml initialization to this object but it doesn't work. In my main I'm trying to run the setCircleLocations but I'm getting nullpointer exception.

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();
}

我的窗口控制器:

public class WindowController {

@FXML
SteeringWheel steeringWheel;
}

此外,在xml文件中,SteeringWheel的子级出现以下错误:Unresolved fx:id reference

in addition, in the xml file I'm getting the following error for the children of the SteeringWheel : Unresolved fx:id reference

堆栈跟踪:

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 注入了适当的字段.您的SteeringWheel类不是控制器,因此不会注入那些@FXML带注释的字段.但是,要注入到这些字段中的对象放在children列表中,因此您可以在那里访问它们.但是,看来您想让SteeringWheel成为其自己的组件,无论如何使用SteeringWheel,两个Circle s和Label总是存在 ,所以它并不试图在单独的位置定义孩子没有意义.

Only the controller has the appropriate fields injected. Your SteeringWheel class is not a controller, thus those @FXML annotated fields are not injected. The objects you intend to be injected into those fields are put in the children list, though, so you could access them there. However, it appears you want SteeringWheel to be its own component, where the two Circles and Label are always present, regardless of how the SteeringWheel is used, so it doesn't make sense to try and define the children in a separate location.

由于要扩展Region,因此您可能需要考虑使用

Since you are extending Region you may want to consider using 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")注释).

Note: I extended Pane instead of Region. The former already extends the latter and already makes the changes you made (i.e. makes the #getChildren() method public and adds a @DefaultProperty("children") annotation).

注意::我覆盖了#layoutChildren(),以便无论父级最终以什么尺寸出现,您的圆都将保留在中心.但是,将它们简单地包装在其他布局中可能会更容易,例如StackPane.

Note: I overrode #layoutChildren() so that your circles remain in the center no matter what dimensions the parent ends up with. However, it may be easier to simply wrap them in some other layout, such as a StackPane.

然后,您只需在其他FXML文件中使用SteeringWheel:

Then you would just use SteeringWheel in your other FXML file:

<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>
    .....

这篇关于将嵌套对象从fxml映射到对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆