访问 GridPane 节点的问题
Problems with accessing GridPane Node
我希望你能帮我做一个我想做的小项目。我正在尝试使用 JavaFX 为 GUI 创建一个视频游戏,但我遇到了一些麻烦。这是我为练习而制作的代码,我不知道为什么这不起作用。
public class Main extends Application {
public GridPane map;
private int MAXH = 40;
private int MAXV = 40;
Random r = new Random();
@Override
public void start(Stage primaryStage) throws Exception{
map = new GridPane();
map.setGridLinesVisible(true);
map.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
//Get X position
int posX = (int) mouseEvent.getX() / 40;
//Get Y position
int posY = (int) mouseEvent.getY() / 40;
System.out.println("(" + posX + " " + posY + ")");
Canvas c = getCanvasNode(map, posX, posY);
}
});
for (int i = 0; i < MAXH; i++){
for(int j = 0; j < MAXV; j++){
//For each cell create a Canvas node
Canvas c = new Canvas(40, 40);
GraphicsContext gc = c.getGraphicsContext2D();
int k = r.nextInt();
//Randomly paint the Canvas
if (k % 3 == 0) gc.setFill(Color.BLUE);
else if (k % 2 == 0) gc.setFill(Color.RED);
else if (k % 7 == 0)gc.setFill(Color.GREEN);
//Filling the Canvas
gc.fillRect(0, 0, 40, 40);
//Adding to our Grid Pane
map.add(c, i, j);
}
}
primaryStage.setHeight(700);
primaryStage.setWidth(1200);
primaryStage.setScene(new Scene(map));
primaryStage.show();
}
private Canvas getCanvasNode(GridPane gridPane, int col, int row) {
for (Node node : gridPane.getChildren()) {
if (GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) {
return (Canvas) node;
}
}
return null;
}
public static void main(String[] args) {
launch(args);
}}
当我使用函数 "getCanvasNode" 时,问题就出现了,它产生了一个空指针异常,我不知道为什么。
我想做的是通过地图获取我点击的节点事件处理程序有人可以帮助我吗?
PD:我不知道这是否是最 efficient/simple 的方法,如果有人能给我一些提示,那就太棒了。我是 Java/JavaFX 的新人。
GridPane.getColumnIndex()
returns Integer
Java Object
,它包装并用作原始 int
[=62= 的装箱] 数据类型。原始数据类型永远不能是 null
,但是 Object
(因此 Integer
)可以分配给 null
。如果我们阅读 GridPane.getColumnIndex()
的 java api 文档,它说,
Returns:
the column index for the child or null if no column index was
set
它可以 return 为空。声明
if (GridPane.getColumnIndex(node) == col) {}
是隐式分解为
Integer colIndex = GridPane.getColumnIndex(node);
int colIndexVal = colIndex.intValue();
if (colIndexVal == col) {}
如果 colIndex
为空,则 colIndex.intValue()
抛出 NullPointerException
。您的代码中发生了什么。
解决方案是考虑空值:
if (GridPane.getColumnIndex(node) != null
&& GridPane.getColumnIndex(node) == col
&& GridPane.getRowIndex(node) != row
&& GridPane.getRowIndex(node) == row) {
return (Canvas) node;
}
另一种方法是将 col 和 row 的参数参数类型更改为 Integer
private Canvas getCanvasNode( GridPane gridPane, Integer col, Integer row )
并使用 equals()
因为现在我们正在比较两个 Integer 对象。这将处理空值:
if ( col.equals( GridPane.getColumnIndex( node ) )
&& row.equals( GridPane.getRowIndex( node ) ) ) {
return ( Canvas ) node;
}
更多信息请继续阅读
- Java 中的数据类型。装箱和拆箱
- 比较 Java 原始类型和对象
关于程序本身,我认为您在那里使用了太多 Canvas
对象。您可以改用 JavaFX Rectangle
或 Label
控件。
根据列值和行值访问子项可以简化为
Node node = gridPane.getChildren().get( col * MAXV + row + 1 );
return (node instanceof Canvas) ? ( Canvas ) node : null;
当你这样做时
for (Node node : gridPane.getChildren()) { ... }
您遍历网格窗格的所有子节点,无论这些节点是您自己添加的节点,还是属于网格窗格内部实现的一部分的节点。
你的情况实际发生的是,因为你已经调用了
map.setGridLinesVisible(true);
网格窗格添加了一个子节点来表示网格线。此节点没有为 columnIndex
或 rowIndex
设置属性。所以当循环遇到那个节点时,GridPane.getColumnIndex(node)
抛出一个 NullPointerException
。 (getColumnIndex
的实现在节点的 属性 映射中查找具有特定键的 Integer
对象,然后在结果上隐式调用 intValue()
。所以如果没有值设置,它会尝试在 null
引用上调用 intValue()
。)
所以你可以按照
的方式做一些事情来解决这个问题
Integer columnIndex = GridPane.getColumnIndex(node);
然后处理特殊情况:
if (columnIndex != null && columnIndex.intValue() == col)
等等
但是,对于您要实现的目标,有一种更好的方法。与其在窗格中注册侦听器,然后深入了解单击了哪个子节点,不如在子节点上注册侦听器:
for (int i = 0; i < MAXH; i++){
for(int j = 0; j < MAXV; j++){
//For each cell create a Canvas node
Canvas c = new Canvas(40, 40);
GraphicsContext gc = c.getGraphicsContext2D();
int k = r.nextInt();
//Randomly paint the Canvas
if (k % 3 == 0) gc.setFill(Color.BLUE);
else if (k % 2 == 0) gc.setFill(Color.RED);
else if (k % 7 == 0)gc.setFill(Color.GREEN);
//Filling the Canvas
gc.fillRect(0, 0, 40, 40);
//Adding to our Grid Pane
map.add(c, i, j);
String message = "Click on cell ["+i+", "+j+"]";
c.setOnMouseClicked(e -> {
System.out.println(message);
// do anything else you need with the canvas....
});
}
}
我希望你能帮我做一个我想做的小项目。我正在尝试使用 JavaFX 为 GUI 创建一个视频游戏,但我遇到了一些麻烦。这是我为练习而制作的代码,我不知道为什么这不起作用。
public class Main extends Application {
public GridPane map;
private int MAXH = 40;
private int MAXV = 40;
Random r = new Random();
@Override
public void start(Stage primaryStage) throws Exception{
map = new GridPane();
map.setGridLinesVisible(true);
map.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
//Get X position
int posX = (int) mouseEvent.getX() / 40;
//Get Y position
int posY = (int) mouseEvent.getY() / 40;
System.out.println("(" + posX + " " + posY + ")");
Canvas c = getCanvasNode(map, posX, posY);
}
});
for (int i = 0; i < MAXH; i++){
for(int j = 0; j < MAXV; j++){
//For each cell create a Canvas node
Canvas c = new Canvas(40, 40);
GraphicsContext gc = c.getGraphicsContext2D();
int k = r.nextInt();
//Randomly paint the Canvas
if (k % 3 == 0) gc.setFill(Color.BLUE);
else if (k % 2 == 0) gc.setFill(Color.RED);
else if (k % 7 == 0)gc.setFill(Color.GREEN);
//Filling the Canvas
gc.fillRect(0, 0, 40, 40);
//Adding to our Grid Pane
map.add(c, i, j);
}
}
primaryStage.setHeight(700);
primaryStage.setWidth(1200);
primaryStage.setScene(new Scene(map));
primaryStage.show();
}
private Canvas getCanvasNode(GridPane gridPane, int col, int row) {
for (Node node : gridPane.getChildren()) {
if (GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) {
return (Canvas) node;
}
}
return null;
}
public static void main(String[] args) {
launch(args);
}}
当我使用函数 "getCanvasNode" 时,问题就出现了,它产生了一个空指针异常,我不知道为什么。
我想做的是通过地图获取我点击的节点事件处理程序有人可以帮助我吗?
PD:我不知道这是否是最 efficient/simple 的方法,如果有人能给我一些提示,那就太棒了。我是 Java/JavaFX 的新人。
GridPane.getColumnIndex()
returns Integer
Java Object
,它包装并用作原始 int
[=62= 的装箱] 数据类型。原始数据类型永远不能是 null
,但是 Object
(因此 Integer
)可以分配给 null
。如果我们阅读 GridPane.getColumnIndex()
的 java api 文档,它说,
Returns:
the column index for the child or null if no column index was set
它可以 return 为空。声明
if (GridPane.getColumnIndex(node) == col) {}
是隐式分解为
Integer colIndex = GridPane.getColumnIndex(node);
int colIndexVal = colIndex.intValue();
if (colIndexVal == col) {}
如果 colIndex
为空,则 colIndex.intValue()
抛出 NullPointerException
。您的代码中发生了什么。
解决方案是考虑空值:
if (GridPane.getColumnIndex(node) != null
&& GridPane.getColumnIndex(node) == col
&& GridPane.getRowIndex(node) != row
&& GridPane.getRowIndex(node) == row) {
return (Canvas) node;
}
另一种方法是将 col 和 row 的参数参数类型更改为 Integer
private Canvas getCanvasNode( GridPane gridPane, Integer col, Integer row )
并使用 equals()
因为现在我们正在比较两个 Integer 对象。这将处理空值:
if ( col.equals( GridPane.getColumnIndex( node ) )
&& row.equals( GridPane.getRowIndex( node ) ) ) {
return ( Canvas ) node;
}
更多信息请继续阅读
- Java 中的数据类型。装箱和拆箱
- 比较 Java 原始类型和对象
关于程序本身,我认为您在那里使用了太多 Canvas
对象。您可以改用 JavaFX Rectangle
或 Label
控件。
根据列值和行值访问子项可以简化为
Node node = gridPane.getChildren().get( col * MAXV + row + 1 );
return (node instanceof Canvas) ? ( Canvas ) node : null;
当你这样做时
for (Node node : gridPane.getChildren()) { ... }
您遍历网格窗格的所有子节点,无论这些节点是您自己添加的节点,还是属于网格窗格内部实现的一部分的节点。
你的情况实际发生的是,因为你已经调用了
map.setGridLinesVisible(true);
网格窗格添加了一个子节点来表示网格线。此节点没有为 columnIndex
或 rowIndex
设置属性。所以当循环遇到那个节点时,GridPane.getColumnIndex(node)
抛出一个 NullPointerException
。 (getColumnIndex
的实现在节点的 属性 映射中查找具有特定键的 Integer
对象,然后在结果上隐式调用 intValue()
。所以如果没有值设置,它会尝试在 null
引用上调用 intValue()
。)
所以你可以按照
的方式做一些事情来解决这个问题Integer columnIndex = GridPane.getColumnIndex(node);
然后处理特殊情况:
if (columnIndex != null && columnIndex.intValue() == col)
等等
但是,对于您要实现的目标,有一种更好的方法。与其在窗格中注册侦听器,然后深入了解单击了哪个子节点,不如在子节点上注册侦听器:
for (int i = 0; i < MAXH; i++){
for(int j = 0; j < MAXV; j++){
//For each cell create a Canvas node
Canvas c = new Canvas(40, 40);
GraphicsContext gc = c.getGraphicsContext2D();
int k = r.nextInt();
//Randomly paint the Canvas
if (k % 3 == 0) gc.setFill(Color.BLUE);
else if (k % 2 == 0) gc.setFill(Color.RED);
else if (k % 7 == 0)gc.setFill(Color.GREEN);
//Filling the Canvas
gc.fillRect(0, 0, 40, 40);
//Adding to our Grid Pane
map.add(c, i, j);
String message = "Click on cell ["+i+", "+j+"]";
c.setOnMouseClicked(e -> {
System.out.println(message);
// do anything else you need with the canvas....
});
}
}