我在fxml文件中的VBox中有一个带标签,文本字段和组合框的窗格。我们称之为tempPane。 在同一个阶段,我有一个按钮。 按下按钮后,我需要向VBox添加一个与tempPane完全相同的窗格。这是,动态地向VBOX添加窗格。 我可以向VBox添加单个控件(如按钮或标签或文本字段),但在尝试添加此新窗格时,我无法获得相同的结果。
部分控制器代码:
@FXML
private Pane tempPane;
@FXML
private Button btnAddNewPane;;
@FXML
private VBox vBox;
@FXML
void addNewPane(ActionEvent event) {
...
Pane newPane = new Pane();
newPane = tempPane;
// New ID is set to the newPane, this String (NewID) should be
//different each time button is pressed
newPane.setId(newID);
vBox.getChildren().add(newPane);
...
}
我得到的错误是:
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Children: duplicate children added: parent = VBox[id=filterBox]
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:580)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at com.sener.dbgui.controller.SearchController$1.run(SearchController.java:53)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
at java.base/java.lang.Thread.run(Thread.java:844)
那么,为什么我得到这个重复的孩子错误?我在更新newPane ID之前将其添加到VBox。
答案 0 :(得分:3)
Pane newPane = new Pane();
newPane = tempPane;
...
vBox.getChildren().add(newPane);
此代码确实会创建一个新的Pane
(第一行),但会立即通过旧实例(第二行)覆盖它来删除新实例。
错误发生,因为Node
的合同不允许在场景中放置两次,而您又添加了Pane
已经是{{1}的孩子的vBox
再次。修改id
属性不会改变这一事实。
如果这应该有效,你需要创建一个以tempPane
为根的子场景的新副本。
您可以为此场景创建自定义Pane
:
<fx:root xmlns:fx="http://javafx.com/fxml" type="javafx.scene.layout.Pane">
<!-- content of tempPane from old fxml goes here -->
...
<Button fx:id="btnAddNewPane" />
...
</fx:root>
public class MyPane extends Pane {
public MyPane() {
FXMLLoader loader = getClass().getResource("subFXML.fxml");
loader.setRoot(this);
loader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
@FXML
private Button btnAddNewPane;
public void setOnAction(EventHandler<ActionEvent> handler) {
btnAddNewPane.setOnAction(handler);
}
public EventHandler<ActionEvent> getOnAction() {
return btnAddNewPane.getOnAction();
}
}
请务必导入MyPane。
...
<VBox fx:id="vBox">
<children>
<!-- replace tempPane with MyPane -->
<MyPane onAction="#addNewPane"/>
</children>
</VBox>
...
@FXML
private VBox vBox;
@FXML
void addNewPane(ActionEvent event) {
...
MyPane newPane = new MyPane();
newPane.setId(newID); // Don't know why setting the CSS id is necessary here
newPane.setOnAction(this::addNewPane); // set onAction property
vBox.getChildren().add(newPane);
...
}
答案 1 :(得分:0)
您的评论中已经写明了您获得重复ID的原因。
//新ID设置为newPane,此String(NewID)应为
每次按下按钮//不同
您正在传递与参数相同的字符串。
newPane.setId("NewID");
尝试为每个窗格使用动态生成的唯一ID。
String newId; //generate the id by user input or internally
newPane.setId(newId);