[英]JavaFX - custom object in FXML file
我的代碼中有以下擴展 JavaFX object :
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 class 來跟蹤 Tile 位置:
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 場景生成器),它使用 GridPane,每個單元格中都有一個 TILE object。 我決定首先在 Scene Builder 中構建一個場景,使用 JavaFX 矩形對象而不是 Tiles,然后手動編輯 .fxml 文件並將其中的 Rectangle 更改為 Tile 對象。 問題是,Intellij 現在告訴我 FXML 文件中的 Tile 對象無法實例化:
...
<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 object 需要將坐標 object 傳遞到其構造函數中,而不是高度和寬度,但我不知道如何將它們粘貼到 FXML 代碼中。 任何幫助將不勝感激。
要允許FXMLLoader
實例化沒有無參數構造函數的類,您需要注釋構造函數參數。 (原因是在 Java 中,參數名稱不保證在運行時保留,因此需要一種機制在運行時根據名稱反射性地將無序值與參數匹配。)請參閱javaFX 中 @NamedArg 注釋的目的是什么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...
}
要在 FXML 中使用它,您可以執行以下操作:
<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
共享相同的Coordinates
實例(可能不適用於此特定用例,但通常它很有用)。
您可以通過 Java 代碼添加組件。
命名您的組件以使用代碼訪問它們。
public class App {
@FXML GridPane examplePane;
public void initialize() {
Tile t = new Tile();
examplePane.add(t);
...
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.