我希望你能帮助我完成一个我想做的小项目。我正在尝试使用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:我不知道这是否是最有效/最简单的方法,如果有人可以给我一些提示,那将是非常棒的。我是Java / JavaFX的新手。答案 0 :(得分:1)
GridPane.getColumnIndex()
返回Integer
Java Object
,它包装并用作原始int
Java数据类型的装箱。原始数据类型永远不能是null
,但Object
(因此Integer
)可以分配给null
。如果我们阅读GridPane.getColumnIndex()
的java api文档,那么
<强>返回:强>
子列的索引,如果没有列索引,则为null 设置
它可以返回null。声明
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;
}
欲了解更多信息,请阅读
关于程序本身,我认为你在那里使用了太多Canvas
个对象。您可以使用JavaFX Rectangle
或Label
控件。
根据col&amp; amp; amp;行值可以简化为
Node node = gridPane.getChildren().get( col * MAXV + row + 1 );
return (node instanceof Canvas) ? ( Canvas ) node : null;
答案 1 :(得分:0)
当你这样做时
for (Node node : gridPane.getChildren()) { ... }
遍历网格窗格的所有子节点,无论这些节点是您自己添加的节点,还是属于网格窗格内部实现的节点。
你的案件实际发生的是,因为你已经打电话了
map.setGridLinesVisible(true);
网格窗格添加了一个子节点来表示网格线。此节点没有为columnIndex
或rowIndex
设置的属性。因此,当循环遇到该节点时,GridPane.getColumnIndex(node)
会抛出NullPointerException
。 (getColumnIndex
的实现在节点的属性映射中查找具有特定键的Integer
对象,然后在结果上隐式调用intValue()
。因此,如果未设置任何值,则尝试在intValue()
引用上致电null
。)
所以你可以通过做一些
的事情来解决这个问题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....
});
}
}