JavaFXGridPane搜索返回空节点
我想从FXML文件在JavaFX中实现我自己的自定义对话框,并希望以编程方式更改对话框的标题和消息。我的.fxml文件具有以下结构:对于一个典型的对话框,我在本例中使用了一个错误对话框:JavaFXGridPane搜索返回空节点,java,javafx,nullpointerexception,Java,Javafx,Nullpointerexception,我想从FXML文件在JavaFX中实现我自己的自定义对话框,并希望以编程方式更改对话框的标题和消息。我的.fxml文件具有以下结构:对于一个典型的对话框,我在本例中使用了一个错误对话框: <StackPane prefHeight="140.0" prefWidth="290.0" style="-fx-background-color: #333333;" stylesheets="/style.css" xmlns="http://javafx.com/javaf
<StackPane prefHeight="140.0" prefWidth="290.0" style="-fx-background-color: #333333;" stylesheets="/style.css"
xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="apps.utils.Dialogs">
<children>
<BorderPane>
<center>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Label text="Error msg" textFill="LIGHTGRAY"/>
<Text fill="LIGHTGRAY" strokeType="OUTSIDE" strokeWidth="0.0"
text="My custom error message here"
wrappingWidth="250.0" GridPane.rowIndex="1">
<GridPane.margin>
<Insets top="10.0"/>
</GridPane.margin>
</Text>
<JFXButton onMouseClicked="#close"
style="-fx-background-color: #da294f; -fx-border-radius: 5; -fx-background-radius: 5;"
text="Retry" textFill="LIGHTGRAY" GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="BASELINE">
<GridPane.margin>
<Insets top="20.0"/>
</GridPane.margin>
</JFXButton>
</children>
</GridPane>
</center>
<StackPane.margin>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</StackPane.margin>
</BorderPane>
</children>
</StackPane>
用于在控制器类中显示对话框的方法:
public static void showDialog(StackPane rootPane, BorderPane rootBorderPane, URL dialogFile, String title, String message) throws IOException {
rootBorderPane.setEffect(boxBlur);
FXMLLoader loader = new FXMLLoader(dialogFile);
loader.setClassLoader(cachingClassLoader);
StackPane dialog = loader.load();
ObservableList<Node> components = dialog.getChildren();
BorderPane pane = (BorderPane) components.get(0);
GridPane content = (GridPane) pane.getCenter();
System.out.println("row: " + content.getRowCount() + " col:" + content.getColumnCount()); //prints Row 3, col 1
Label dialogTitle = (Label) findNodeFromIndex(content, 0, 0);
dialogTitle.setText(title);
Text dialogMessage = (Text) findNodeFromIndex(content, 0, 1);
dialogMessage.setText(message);
//rest of the code to show dialog...
}
然后我有一个功能,可以像这样在Gridpane中搜索:
private static Node findNodeFromIndex(GridPane gridPane, int col, int row) {
for (int i = 0; i < gridPane.getChildren().size(); i++) {
Node node = gridPane.getChildren().get(i);
if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == col) {
return node;
}
}
return null;
}
然后,我只需使用对话框类型、标题以及自定义标题/正文文本作为参数调用showDialog
现在我的问题是,我在setText方法上得到了一个NullPointerException。我不明白这是为什么。我怎样才能解决这个问题 我认为findNodeFromIndex返回null,因为您没有在列0中的节点上显式设置列索引,等等
像这样手动搜索场景图根本不是正确的方法。对布局的任何微小更改都将完全破坏此代码。相反,只需在控制器类中定义方法来设置标题和消息:
public class Dialogs {
@FXML
private Label titleLabel ;
@FXML
private Text messageText ;
public void setTitle(String title) {
titleLabel.setText(title);
}
public void setMessage(String message) {
messageText.setText(message);
}
// ...
}
并在FXML中的元素上设置fx:id:
然后您可以调用这些方法:
public static void showDialog(StackPane rootPane, BorderPane rootBorderPane, URL dialogFile, String title, String message) throws IOException {
rootBorderPane.setEffect(boxBlur);
FXMLLoader loader = new FXMLLoader(dialogFile);
loader.setClassLoader(cachingClassLoader);
StackPane dialog = loader.load();
Dialogs controller = loader.getController();
controller.setTitle(title);
controller.setMessage(message);
//rest of the code to show dialog...
}
由于未对某些元素设置行索引,因此在0处搜索时,这些元素将不匹配,因此findNodeFromIndex返回null。无论如何,这是一种非常丑陋的方式;为什么不获取对控制器的引用,并在控制器中定义方法来设置标题和消息?然后避免像这样在场景图中搜索,请注意,如果对布局进行任何轻微修改,代码将被破坏得有多严重。哦,可能就是这样。我没有检查fxml文件。我只签入了Scenebuilder,它们显示了行索引。获取控制器的引用是我尝试的第一件事。使用@FXML,但它始终返回空值。我想我必须自己硬编码,但这是我想要避免的。我想得很好,因为我确信我总是把标题和消息作为第一行和第二行,然后我就可以这样做了。我也不想在这上面花太多时间,但事后看来,我花在这另一种方法上的时间现在可能没有什么不同。???只需在调用loader后调用loader.getController,我相信我就是这么做的。我觉得我的控件标题有点不对劲。我知道必须在fxml文件名之后连接控制器。但是你会如何处理这个_角色呢?例如,如果文件的id是my_dialog.fxml。控制器应该是my_dialogController还是myDialogController?我完全不知道你在最后的评论中说的是什么。您发布的代码中没有可见的标记。谢谢。好东西。我错过了loader.getController行