JavaFX - пользовательский объект в файле F XML - PullRequest
0 голосов
/ 11 апреля 2020

В моем коде есть следующий расширенный объект JavaFX:

package shipsinspace.view.board;

import javafx.scene.shape.Rectangle;
import shipsinspace.common.Coordinates;

public class Tile extends Rectangle {
    private Coordinates coordinates;

    public Tile(double width, double height, Coordinates coordinates) {
        super(width, height);
        this.coordinates = coordinates;
    }

    public Coordinates getCoordinates() {
        return coordinates;
    }
}

Он использует класс клиента Java, который я написал для отслеживания местоположения плитки:

package shipsinspace.common;

import java.util.Objects;

public class Coordinates {
    private int xCoordinate;
    private int yCoordinate;

    public Coordinates(int xCoordinate, int yCoordinate) {
        this(xCoordinate, yCoordinate, 10, false);
    }

    public Coordinates(int xCoordinate, int yCoordinate, int max) {
        this(xCoordinate, yCoordinate, max, false);
    }

    public Coordinates(int xCoordinate, int yCoordinate, int max, boolean allowedZero) {
        if (allowedZero) {
            if ((xCoordinate >= 0 && yCoordinate >= 0) && (xCoordinate <= max && yCoordinate <= max)) {
                this.xCoordinate = xCoordinate;
                this.yCoordinate = yCoordinate;
            } else {
                throw new IllegalArgumentException(String.format("Either X or Y has set to value <= 0, or > %d", max));
            }
        } else {
            if ((xCoordinate > 0 && yCoordinate > 0) && (xCoordinate <= max && yCoordinate <= max)) {
                this.xCoordinate = xCoordinate;
                this.yCoordinate = yCoordinate;
            } else {
                throw new IllegalArgumentException(String.format("Either X or Y has set to value <= 0, or > %d", max));
            }
        }

    }

    public int getX() {
        return xCoordinate;
    }

    public int getY() {
        return yCoordinate;
    }

    public Coordinates returnNeighbour(int axis, int direction) {
        if (axis == 0) {
            try {
                return new Coordinates(this.getX() + direction, this.getY());
            } catch (IllegalArgumentException e) {
                return new Coordinates(this.getX(), this.getY());
            }

        } else {
            try {
                return new Coordinates(this.getX(), this.getY() + direction);
            } catch (IllegalArgumentException e) {
                return new Coordinates(this.getX(), this.getY());
            }

        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Coordinates that = (Coordinates) o;
        return xCoordinate == that.xCoordinate &&
                yCoordinate == that.yCoordinate;
    }

    @Override
    public int hashCode() {
        return Objects.hash(xCoordinate, yCoordinate);
    }

    @Override
    public String toString() {
        return String.format("Coordinates (%d, %d)", xCoordinate, yCoordinate);
    }
}

Сейчас Я хотел бы построить сцену (через JavaFX Scene Builder), которая использует GridPane, с объектом TILE в каждой из его ячеек. Я решил сначала построить сцену в Scene Builder, используя объекты JavaFX Rectangle вместо Tiles, а затем вручную отредактировал файл .f xml и изменил Rectangle на объекты Tile. Проблема в том, что теперь Intellij сообщает мне, что объекты Tile в файле F XML невозможно создать:

...
   <center>
      <GridPane BorderPane.alignment="CENTER">
        <columnConstraints>
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>

            <Tile arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="52.0" stroke="BLACK" strokeType="INSIDE" width="53.0" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
               <GridPane.margin>
                  <Insets bottom="1.0" left="1.0" right="1.0" top="1.0" />
               </GridPane.margin>
            </Tile>
...

Я могу сказать, что это потому, что моему объекту Tile требуется передать объект Coordinates. в его конструктор, кроме высоты и ширины, но я не могу понять, как вставить их в код F XML. Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

Чтобы позволить FXMLLoader создавать экземпляры классов без конструкторов без аргументов, необходимо аннотировать параметры конструктора. (Причина этого в том, что в Java имена параметров не гарантированно сохраняются во время выполнения, поэтому необходим механизм для отражательного сопоставления неупорядоченных значений с параметрами, основанными на именах во время выполнения.) См. Какова цель @NamedArg аннотация в javaFX 8? для получения дополнительной информации.

Так что ваши классы Tile и Coordinates теперь выглядят так:

import javafx.beans.NamedArg;
import javafx.scene.shape.Rectangle;

public class Tile extends Rectangle {
    private Coordinates coordinates;

    public Tile(
            @NamedArg("width") double width,
            @NamedArg("height") double height,
            @NamedArg("coordinates") Coordinates coordinates) {
        super(width, height);
        this.coordinates = coordinates;
    }

    public Coordinates getCoordinates() {
        return coordinates;
    }
}
import java.util.Objects;

import javafx.beans.NamedArg;

public class Coordinates {
    private int xCoordinate;
    private int yCoordinate;

    public Coordinates(
            @NamedArg("xCoordinate") int xCoordinate,
            @NamedArg("yCoordinate") int yCoordinate) {
        this(xCoordinate, yCoordinate, 10, false);
    }

    public Coordinates(
            @NamedArg("xCoordinate") int xCoordinate, 
            @NamedArg("yCoordinate") int yCoordinate,
            @NamedArg("max") int max) {
        this(xCoordinate, yCoordinate, max, false);
    }

    public Coordinates(
            @NamedArg("xCoordinate") int xCoordinate,
            @NamedArg("yCoordinate") int yCoordinate,
            @NamedArg("max") int max,
            @NamedArg("allowedZero") boolean allowedZero) {
        if (allowedZero) {
            if ((xCoordinate >= 0 && yCoordinate >= 0) && (xCoordinate <= max && yCoordinate <= max)) {
                this.xCoordinate = xCoordinate;
                this.yCoordinate = yCoordinate;
            } else {
                throw new IllegalArgumentException(String.format("Either X or Y has set to value <= 0, or > %d", max));
            }
        } else {
            if ((xCoordinate > 0 && yCoordinate > 0) && (xCoordinate <= max && yCoordinate <= max)) {
                this.xCoordinate = xCoordinate;
                this.yCoordinate = yCoordinate;
            } else {
                throw new IllegalArgumentException(String.format("Either X or Y has set to value <= 0, or > %d", max));
            }
        }

    }

    // remaining code unaltered...
}

Чтобы использовать это в F XML, вы можете сделать:

<Tile width="100.0" height="100.0">
    <coordinates>
        <Coordinates xCoordinate="1" yCoordinate="1"/>
    </coordinates>
</Tile>

или

<fx:define>
    <Coordinates fx:id="tileCoordinates" xCoordinate="1" yCoordinate="1" />
</fx:define>
<Tile width="100.0" height="100.0" coordinates="$tileCoordinates" />

Выбор между ними в основном просто выбор стиля; однако обратите внимание, что последние опции дают вам возможность нескольким Tile s совместно использовать один и тот же экземпляр Coordinates (вероятно, не применим в данном конкретном случае использования, но в целом это может быть полезно).

0 голосов
/ 11 апреля 2020

Вы можете добавить компонент с помощью Java кода.

Назовите свои компоненты для доступа к ним с помощью кода.

public class App {
    @FXML GridPane examplePane;

    public void initialize() {
        Tile t = new Tile();
        examplePane.add(t);
        ...
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...