如何按网格中的位置从 GridPane 中删除节点(Circle 和 Button 对象)?
How to remove nodes (Circle and Button objects) from GridPane by location in the grid?
我在这个问题上停留了很长一段时间,我们正在处理一个 FXML 文件。我已经从这里看到并实现了这段代码:JavaFX: Get Node by row and column
public Node getNodeByRowColumnIndex(final int row,final int column,GridPane gridPane) {
Node result = null;
ObservableList<Node> childrens = gridPane.getChildren();
for(Node node : childrens) {
if(gridPane.getRowIndex(node) == row && gridPane.getColumnIndex(node) == column) {
result = node;
break;
}
}
return result;
}
这适用于我们在开始时在 FXML 文件中添加的所有节点,但对于我们稍后在程序(游戏)的 运行 期间手动添加的节点,它不起作用.然后它得到一个空指针异常。如果我们打印出节点,我们会为在 运行 时间添加的节点得到这个:Group@181fe7
因此是一个内存地址。对于在 运行 之前在 fxml 文件中添加的节点,我们确实得到了一个包含节点信息的漂亮字符串,因此以某种方式向网格添加节点与在 fxml 中完成的方式不同。我们通过以下代码手动添加节点:
private void addSheep(Point point) {
Circle sheep = new Circle(25);
sheep.setFill(Color.BLUE);
sheep.setOnMouseClicked(this::sheepSelected);
pane.add(sheep, point.x, point.y);
GridPane.setHalignment(animal, HPos.CENTER);
}
为什么会这么难?我只想找到网格窗格中特定单元格上的内容,然后删除位于那里的一个对象。我为一些看似微不足道的事情花费了大量时间。
您在某处向 GridPane
添加了一些节点,但未指定 columnIndex
和 rowIndex
。 (在某些情况下,即使您没有自己明确添加它们,也会发生这种情况。例如,您在 GridPane
上将 gridLinesVisible
设置为 true
。)看起来至少其中一个节点是 Group
;您描述的输出是来自 Group
实例的 toString()
的默认实现。
GridPane
内部管理网格位置的方式是通过每个节点的property map设置特定值;此映射中列索引和行索引的值是 Integer
属性。 getColumnIndex()
和 getRowIndex()
检索那些 Integer
属性并有效地调用它们的 intValue()
,所以如果它们没有设置,你会得到一个 NullPointerException
。
所以一个快速的解决办法可能是做一些像
public Node getNodeByRowColumnIndex(final int row,final int column,GridPane gridPane) {
Node result = null;
ObservableList<Node> childrens = gridPane.getChildren();
for(Node node : childrens) {
if(node instanceof Circle && gridPane.getRowIndex(node) == row && gridPane.getColumnIndex(node) == column) {
result = node;
break;
}
}
return result;
}
如果您添加的列索引和行索引设置正确(并且您感兴趣)的所有节点都是 Circle
,这将起作用。显然,您可以添加一些其他逻辑来解决其他情况。
您在此处 运行 遇到困难的原因是您正在有效地尝试从视图组件 (GridPane
) 检索数据(某个位置的内容)。这是一个反模式:视图不应该存储应用程序数据,它们应该只是被动地观察它(至多)。如果您对该项目仍有大量工作要做,您可能应该考虑对其进行重组,使其以数据为中心。
以下是一些代码片段,可以帮助您理解我的意思:
public class Sheep {
// data for intrinsic state of sheep omitted..
private final Circle view ;
public Sheep() {
this.view = new Circle(...);
// configure view...
}
public Node getView() {
return view ;
}
// logic etc... manipulates intrinsic state of sheep....
}
确保实现 Point
以便它可以在集合中正确使用:
public class Point {
final int x, y ;
@Override
public boolean equals(Object other) {
if (other.getClass() != Point.class) {
return false ;
}
Point o = (Point)other ;
return o.x == x && o.y == y ;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
游戏代码:
ObservableMap<Point, Sheep> allSheep = FXCollections.observableHashMap();
GridPane gameView = new GridPane();
allSheep.addListener((Change<? extends Point, ? extends Sheep> c) -> {
if (c.wasAdded()) {
Point location = c.getKey();
Sheep addedSheep = c.getValue();
gameView.add(addedSheep.getView(), location.x, location.y);
} else if (c.wasRemoved()) {
Sheep removedSheep = c.getValue();
gameView.getChildren().remove(removedSheep.getView());
}
}
现在视图已有效地设置为自行管理,您只需处理数据,只需操作绵羊的位置图即可:
public void addSheep(int x, int y) {
allSheep.put(new Point(x,y), new Sheep());
}
public void removeSheep(int x, int y) {
allSheep.remove(new Point(x, y));
}
请注意地图包含与游戏相关的所有数据,因此您可以随时检查它并进行适当的更改。您应该能够将该逻辑与游戏的 "view" 分开,并且只需 controller/presenter 类型 类 封装它们之间的 link (例如,定义的地图侦听器上面,它会在地图中的条目更改时更新网格)。
我在这个问题上停留了很长一段时间,我们正在处理一个 FXML 文件。我已经从这里看到并实现了这段代码:JavaFX: Get Node by row and column
public Node getNodeByRowColumnIndex(final int row,final int column,GridPane gridPane) {
Node result = null;
ObservableList<Node> childrens = gridPane.getChildren();
for(Node node : childrens) {
if(gridPane.getRowIndex(node) == row && gridPane.getColumnIndex(node) == column) {
result = node;
break;
}
}
return result;
}
这适用于我们在开始时在 FXML 文件中添加的所有节点,但对于我们稍后在程序(游戏)的 运行 期间手动添加的节点,它不起作用.然后它得到一个空指针异常。如果我们打印出节点,我们会为在 运行 时间添加的节点得到这个:Group@181fe7
因此是一个内存地址。对于在 运行 之前在 fxml 文件中添加的节点,我们确实得到了一个包含节点信息的漂亮字符串,因此以某种方式向网格添加节点与在 fxml 中完成的方式不同。我们通过以下代码手动添加节点:
private void addSheep(Point point) {
Circle sheep = new Circle(25);
sheep.setFill(Color.BLUE);
sheep.setOnMouseClicked(this::sheepSelected);
pane.add(sheep, point.x, point.y);
GridPane.setHalignment(animal, HPos.CENTER);
}
为什么会这么难?我只想找到网格窗格中特定单元格上的内容,然后删除位于那里的一个对象。我为一些看似微不足道的事情花费了大量时间。
您在某处向 GridPane
添加了一些节点,但未指定 columnIndex
和 rowIndex
。 (在某些情况下,即使您没有自己明确添加它们,也会发生这种情况。例如,您在 GridPane
上将 gridLinesVisible
设置为 true
。)看起来至少其中一个节点是 Group
;您描述的输出是来自 Group
实例的 toString()
的默认实现。
GridPane
内部管理网格位置的方式是通过每个节点的property map设置特定值;此映射中列索引和行索引的值是 Integer
属性。 getColumnIndex()
和 getRowIndex()
检索那些 Integer
属性并有效地调用它们的 intValue()
,所以如果它们没有设置,你会得到一个 NullPointerException
。
所以一个快速的解决办法可能是做一些像
public Node getNodeByRowColumnIndex(final int row,final int column,GridPane gridPane) {
Node result = null;
ObservableList<Node> childrens = gridPane.getChildren();
for(Node node : childrens) {
if(node instanceof Circle && gridPane.getRowIndex(node) == row && gridPane.getColumnIndex(node) == column) {
result = node;
break;
}
}
return result;
}
如果您添加的列索引和行索引设置正确(并且您感兴趣)的所有节点都是 Circle
,这将起作用。显然,您可以添加一些其他逻辑来解决其他情况。
您在此处 运行 遇到困难的原因是您正在有效地尝试从视图组件 (GridPane
) 检索数据(某个位置的内容)。这是一个反模式:视图不应该存储应用程序数据,它们应该只是被动地观察它(至多)。如果您对该项目仍有大量工作要做,您可能应该考虑对其进行重组,使其以数据为中心。
以下是一些代码片段,可以帮助您理解我的意思:
public class Sheep {
// data for intrinsic state of sheep omitted..
private final Circle view ;
public Sheep() {
this.view = new Circle(...);
// configure view...
}
public Node getView() {
return view ;
}
// logic etc... manipulates intrinsic state of sheep....
}
确保实现 Point
以便它可以在集合中正确使用:
public class Point {
final int x, y ;
@Override
public boolean equals(Object other) {
if (other.getClass() != Point.class) {
return false ;
}
Point o = (Point)other ;
return o.x == x && o.y == y ;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
游戏代码:
ObservableMap<Point, Sheep> allSheep = FXCollections.observableHashMap();
GridPane gameView = new GridPane();
allSheep.addListener((Change<? extends Point, ? extends Sheep> c) -> {
if (c.wasAdded()) {
Point location = c.getKey();
Sheep addedSheep = c.getValue();
gameView.add(addedSheep.getView(), location.x, location.y);
} else if (c.wasRemoved()) {
Sheep removedSheep = c.getValue();
gameView.getChildren().remove(removedSheep.getView());
}
}
现在视图已有效地设置为自行管理,您只需处理数据,只需操作绵羊的位置图即可:
public void addSheep(int x, int y) {
allSheep.put(new Point(x,y), new Sheep());
}
public void removeSheep(int x, int y) {
allSheep.remove(new Point(x, y));
}
请注意地图包含与游戏相关的所有数据,因此您可以随时检查它并进行适当的更改。您应该能够将该逻辑与游戏的 "view" 分开,并且只需 controller/presenter 类型 类 封装它们之间的 link (例如,定义的地图侦听器上面,它会在地图中的条目更改时更新网格)。