1

i have this issue with javaFX GUI ... i want when i press button i verify if there is no empty pane else i Add a new pane .. but every time i get ConcurrentModificationException . i have tried with print and i see that only the first section of for here is executed and not the other

enter code here
    button.setOnAction(new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(ActionEvent event) {
                        for (Node node : vbox.getChildren()) {
                            if (node instanceof Pane){
                                Pane pane = (Pane) node ;
                                if (pane.getChildren().isEmpty()){
                                    vbox.getChildren().remove(node);
                                }
                            }``
                        }
                        drugrow drug = new drugrow();
                        vbox.getChildren().addAll(drug.getPane());
                    }
                });
  • 1
    Calling Platform.runlater will remove the nodes at some more or less unspecified point in the future and also creates a Runnable for each node you want removed. – Björn Zurmaar Jul 20 '17 at 19:25
  • 1
    @SedrickJefferson `Platform.runLater(...)` is used to execute a block of code on the FX Application thread when the current code is executed on a background thread. This question has nothing to do with threading. That actually works in this case (because of the way `Platform.runLater(...)` happens to be implemented when called from the FX Application Thread) but is a hack at best. – James_D Jul 20 '17 at 19:47
  • Thanks for the info. I have been doing this wrong the whole time. – SedJ601 Jul 20 '17 at 19:49

1 Answers1

2

You're iterating over the list of vbox's child nodes in your for each loop and at the same time you remove the nodes from that list in the loops body. The iterator then notifies that the lists state changed and hence throws a ConcurrentModificationException because it is not capable of keeping track of the changes and guaranteeing that the iteration happens in an orderly fashion. These kind of iterators are called fail fast iterators.

The better approach is to collect the nodes you want removed and remove them after you have finnished iterating over the list.

button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                final List<Node> removalCandidates = new ArrayList<>();
                for (Node node : vbox.getChildren()) {
                    if (node instanceof Pane){
                        Pane pane = (Pane) node ;
                        if (pane.getChildren().isEmpty()){
                            removalCandidates.add(node);
                        }
                    }
                }
                vbox.getChildren().removeAll(removalCandidates);
                drugrow drug = new drugrow();
                vbox.getChildren().addAll(drug.getPane());
            }
        });
Björn Zurmaar
  • 826
  • 1
  • 9
  • 22
  • 1
    Or, more simply, `vbox.getChildren().removeIf(node -> node instanceof Pane && ((Pane)node).getChildren().isEmpty);` – James_D Jul 20 '17 at 19:24