отображение вложенного объекта из f xml в объект - PullRequest
0 голосов
/ 16 января 2020

Я создал следующий объект, который должен отвечать за отображение рулевого колеса в моем приложении 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);
    }

, и мой файл f xml содержит следующее объявление:

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

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

трассировка стека:

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

1 Ответ

1 голос
/ 16 января 2020

Только контроллер имеет соответствующие поля. Ваш класс SteeringWheel не является контроллером, поэтому аннотированные поля @FXML не вводятся. Объекты, которые вы намереваетесь ввести в эти поля, помещаются в список children, поэтому вы могли бы получить к ним доступ там. Однако кажется, что вы хотите, чтобы SteeringWheel был его собственным компонентом, где два Circle s и 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() publi c и добавляет аннотацию @DefaultProperty("children")).

Примечание : Я перебил #layoutChildren(), чтобы ваши круги оставались в центре независимо от того, с какими размерами заканчивается родитель. Однако может быть проще просто обернуть их в какой-то другой макет, например StackPane.

Тогда вы просто используете SteeringWheel в другом файле F XML:

<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>
    .....
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...