在JavaFX中访问GridPane的列和行索引会一直返回null

时间:2016-08-27 08:17:46

标签: javafx

大家好,所以我在网上尝试了很多关于如何获取在Gridpane中点击的Node(单元格)的解决方案。我用于获取节点的方法如下所示。我也尝试在此方法之前迭代所有节点。我用scenebuilder构建了gridpane,正如你在下面的图片中看到的那样,列和行显然都在那里。我正在尝试此解决方案How to get GridPane Row and Column IDs on Mouse Entered in each cell of Grid in JavaFX?但是正如我上面提到的,从行和列返回的值为空。

@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());
    }

enter image description here

包含此网格的FXML

<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>

1 个答案:

答案 0 :(得分:2)

事件的来源是Node,其中添加了处理程序,即在这种情况下GridPane。您可以将处理程序添加到GridPane的子项中,以使源Node正确无误:

<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>

请注意,您也可以使用原始fxml进行此操作。但是,您应该考虑以下几点:

  1. null也是GridPane.getRowIndexGridPane.getColumnIndex的有效返回值,这并不意味着该节点不是GridPane的子节点,它只是意味着该值未从默认值更改。这与使用值0
  2. 具有相同的效果
  3. 条件

    if (colIndex == null && rowIndex == null)
    

    太强大,无法阻止其他部分NullPointerException。这可能发生在例如如果点击了Separator

  4. 事件的目标是实际点击的节点,可以是Node皮肤中的Label。在此节点中,您可以遍历父节点,直到父节点为GridPane,以查找GridPane的正确子节点。
  5. @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());
        }
    }
    

    请注意,除非您将首选大小设置为大于Label约束,否则GridPane不会填满GridPane。这会弄乱GridPane的布局。解决方法是将Region放在单元格中的Label后面。这些可以使用单元格调整大小而不影响GridPane布局,这允许您在这些节点上捕获事件:

    <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>