Reputation: 823
Hi so I have tried many solutions online on how to get the Node(cell) that was clicked on in the Gridpane. The method I went with for getting the node is shown below. I have also tried iterating through all the nodes prior to this method. I have built the gridpane with scenebuilder and as you can see in the picture below the columns and row are clearly there. I am trying this solution How to get GridPane Row and Column IDs on Mouse Entered in each cell of Grid in JavaFX? however as I've mentioned above the values returned from the rows and columns are null.
@FXML
private void mouseEntered(MouseEvent e) {
Node source = (Node)e.getSource() ;
System.out.println(source);
Integer colIndex = userSelectionGrid.getColumnIndex(source);
Integer rowIndex = userSelectionGrid.getRowIndex(source);
if (colIndex == null && rowIndex == null) System.out.println("BOO");
else
System.out.printf("Mouse entered cell [%d, %d]%n", colIndex.intValue(), rowIndex.intValue());
}
FXML containing this grid
<GridPane fx:id="userSelectionGrid" onMouseClicked="#mouseEntered" prefHeight="44.0" prefWidth="563.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="SAVE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Label text="CANCEL" GridPane.columnIndex="0" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Separator orientation="VERTICAL" GridPane.columnIndex="1" />
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</GridPane>
Upvotes: 0
Views: 2656
Reputation: 82461
The source of the event is the Node
where the handler is added, i.e. in this case the GridPane
. You could add the handlers to the children of the GridPane
for the source Node
to be correct:
<GridPane fx:id="userSelectionGrid" prefHeight="44.0" prefWidth="563.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="SAVE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="0" onMouseClicked="#mouseEntered">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Label text="CANCEL" GridPane.columnIndex="0" GridPane.halignment="CENTER" GridPane.rowIndex="0" onMouseClicked="#mouseEntered">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Separator orientation="VERTICAL" GridPane.columnIndex="1" />
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</GridPane>
Note that you could also make this work with your original fxml. However there are a few things that you should consider:
null
is also a valid return value for GridPane.getRowIndex
and GridPane.getColumnIndex
this doesn't mean the node is not the child of a GridPane
, it just means the value has not been changed from the default. This has the same effect as using the value 0
.The condition
if (colIndex == null && rowIndex == null)
Is too strong to prevent a NullPointerException
in the else part. This could occur e.g. if the Separator
is clicked.
Node
in the Label
's skin. From this node you could traverse to the parent node until the parent is the GridPane
to find the correct child of the GridPane
.@FXML
private void mouseEntered(MouseEvent e) {
Node target = (Node) e.getTarget();
// traverse towards root until userSelectionGrid is the parent node
if (target != userSelectionGrid) {
Node parent;
while ((parent = target.getParent()) != userSelectionGrid) {
target = parent;
}
}
Integer colIndex = userSelectionGrid.getColumnIndex(target);
Integer rowIndex = userSelectionGrid.getRowIndex(target);
if (colIndex == null || rowIndex == null) {
System.out.println("BOO");
} else {
System.out.printf("Mouse entered cell [%d, %d]%n", colIndex.intValue(), rowIndex.intValue());
}
}
Note that the Label
s do not fill the full GridPane
unless you set the preferred size larger than the GridPane
constraints. This messes up the layout of the GridPane
. A workaround would be placing Region
s behind the Label
s in the cells. Those can be resized with the cells without influence on the GridPane
layout, which allows you to catch the event on those nodes:
<GridPane fx:id="userSelectionGrid" prefHeight="44.0" prefWidth="563.0" onMouseClicked="#mouseEntered">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" fillWidth="true" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" fillWidth="true" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" fillHeight="true" />
</rowConstraints>
<children>
<Region GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<Region GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<Label text="SAVE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Label text="CANCEL" GridPane.columnIndex="0" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Separator orientation="VERTICAL" GridPane.columnIndex="1" />
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</GridPane>
Upvotes: 2