无法循环遍历 FXML 元素并将其中一些元素添加到列表中
Trouble looping through FXML elements and adding some of them to a list
我发现 this question 非常有帮助,但我仍然无法让我的循环正常工作。
预期:
我正在构建一个带有 UI 的简单 JavaFX 应用程序,该应用程序通过几个 TextFields 和几个按钮接收输入。我已经构建了一个 "Reset" 按钮,可以清除所有 TextFields 中的文本,但我无法让它工作。
按钮的方法循环遍历 FXML 元素,我希望它能识别 TextFields 并将它们添加到列表中:
private List<TextField> identifyTextFields(Pane parent) {
List<TextField> textFieldList = new ArrayList<>();
for (Node element : parent.getChildren()) {
if (element instanceof Pane) {
// if element is a container, scan its children
scanNodesForTextFields((Pane) element);
//This line is always false. Why?
if (element instanceof TextField) {
textFieldList.addAll(scanNodesForTextFields((Pane) element));
}
} else if (element instanceof TextField) {
textFieldList.add((TextField) element);
}
}
return textFieldList;
}
然后,textFieldList 返回到此方法,其中循环遍历并清除 textField:
@FXML
public void resetButtonClicked(ActionEvent event) {
List<TextField> textFieldList = identifyTextFields(parentNode);
for (TextField textField : textFieldList) {
textField.setText("");
}
}
现实:
在
identifyTextFields(Pane parent)
方法,这一行总是假的:
if (element instanceof TextField) {
我不明白为什么。我试图遍历 FXML 场景图的所有元素,从根节点开始,它是一个锚窗格。如果内部循环发现其中一个元素是 TextField,则应将其添加到列表中...但它永远找不到任何 TextField。
我在理解调试结果时也遇到了一些麻烦,但在我看来该方法甚至没有访问 TextFields;就好像它直接跳过了它们。
我的方法有什么问题吗?
作为参考,下面是包含我定位的 6 个 TextField 的场景图:
<AnchorPane fx:id="parentNode" prefHeight="758.0"
prefWidth="662.0" xmlns="http://javafx.com/javafx/8.0.171"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="Controller">
<children>
...snip...
<HBox fx:id="textFieldContainer" layoutY="378.0" prefHeight="100.0" prefWidth="660.0">
<children>
<VBox prefHeight="100.0" prefWidth="110.0">
<children>
<Label text="1">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldOne">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="100.0" prefWidth="110.0">
<children>
<Label text="2">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldTwo">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="3">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldThree">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="4">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldFour">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="5">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldFive">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="6">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldSix">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
</children></HBox>
...snip...
您可以使用基于 CSS 选择器的 lookup 为 "TextField" css 类型递归查找给定父节点的所有文本字段。
@SuppressWarnings("unchecked")
private Set<TextField> lookupTextFields(Parent parent) {
return (Set<TextField>)(Set<?>) parent.lookupAll("TextField");
}
奇型铸件来自:
- How do you cast a List of supertypes to a List of subtypes?
有时,为了使查找功能正常运行,您需要生成布局通道;见:
- Get the height of a node in JavaFX (generate a layout pass)
这是通过在调用 lookupAll
之前调用以下代码来完成的:
parent.applyCss();
parent.layout();
但是,对于您的特定情况,不太可能需要生成布局过程。 FXML 加载器在 FXML 加载调用期间已经构建了足够的场景图,因此基于 "TextField" css 选择器的查找将起作用。
我发现 this question 非常有帮助,但我仍然无法让我的循环正常工作。
预期:
我正在构建一个带有 UI 的简单 JavaFX 应用程序,该应用程序通过几个 TextFields 和几个按钮接收输入。我已经构建了一个 "Reset" 按钮,可以清除所有 TextFields 中的文本,但我无法让它工作。
按钮的方法循环遍历 FXML 元素,我希望它能识别 TextFields 并将它们添加到列表中:
private List<TextField> identifyTextFields(Pane parent) {
List<TextField> textFieldList = new ArrayList<>();
for (Node element : parent.getChildren()) {
if (element instanceof Pane) {
// if element is a container, scan its children
scanNodesForTextFields((Pane) element);
//This line is always false. Why?
if (element instanceof TextField) {
textFieldList.addAll(scanNodesForTextFields((Pane) element));
}
} else if (element instanceof TextField) {
textFieldList.add((TextField) element);
}
}
return textFieldList;
}
然后,textFieldList 返回到此方法,其中循环遍历并清除 textField:
@FXML
public void resetButtonClicked(ActionEvent event) {
List<TextField> textFieldList = identifyTextFields(parentNode);
for (TextField textField : textFieldList) {
textField.setText("");
}
}
现实:
在
identifyTextFields(Pane parent)
方法,这一行总是假的:
if (element instanceof TextField) {
我不明白为什么。我试图遍历 FXML 场景图的所有元素,从根节点开始,它是一个锚窗格。如果内部循环发现其中一个元素是 TextField,则应将其添加到列表中...但它永远找不到任何 TextField。
我在理解调试结果时也遇到了一些麻烦,但在我看来该方法甚至没有访问 TextFields;就好像它直接跳过了它们。
我的方法有什么问题吗?
作为参考,下面是包含我定位的 6 个 TextField 的场景图:
<AnchorPane fx:id="parentNode" prefHeight="758.0"
prefWidth="662.0" xmlns="http://javafx.com/javafx/8.0.171"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="Controller">
<children>
...snip...
<HBox fx:id="textFieldContainer" layoutY="378.0" prefHeight="100.0" prefWidth="660.0">
<children>
<VBox prefHeight="100.0" prefWidth="110.0">
<children>
<Label text="1">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldOne">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="100.0" prefWidth="110.0">
<children>
<Label text="2">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldTwo">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="3">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldThree">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="4">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldFour">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="5">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldFive">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
<VBox prefHeight="200.0" prefWidth="110.0">
<children>
<Label text="6">
<padding>
<Insets left="30.0" />
</padding>
<font>
<Font name="Calibri" size="16.0" />
</font>
</Label>
<TextField fx:id="textFieldSix">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</TextField>
</children>
</VBox>
</children></HBox>
...snip...
您可以使用基于 CSS 选择器的 lookup 为 "TextField" css 类型递归查找给定父节点的所有文本字段。
@SuppressWarnings("unchecked")
private Set<TextField> lookupTextFields(Parent parent) {
return (Set<TextField>)(Set<?>) parent.lookupAll("TextField");
}
奇型铸件来自:
- How do you cast a List of supertypes to a List of subtypes?
有时,为了使查找功能正常运行,您需要生成布局通道;见:
- Get the height of a node in JavaFX (generate a layout pass)
这是通过在调用 lookupAll
之前调用以下代码来完成的:
parent.applyCss();
parent.layout();
但是,对于您的特定情况,不太可能需要生成布局过程。 FXML 加载器在 FXML 加载调用期间已经构建了足够的场景图,因此基于 "TextField" css 选择器的查找将起作用。