0

I'm using LiveList to bind the children of a group to a list containing the data of the children. here is an example:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        ObservableList<Integer> intList = FXCollections.observableArrayList();
        LiveList<Circle> circleList = LiveList.map(intList, i -> {
            System.out.println("in");
            return new Circle(i);
        });

        Group group = new Group();
        Bindings.bindContent(group.getChildren(), circleList);

        intList.add(2);
        intList.clear();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

My problem is that for each change in intList the bound list is updated twice and which creates more objects than needed. Running the code gives:

in
in
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Children: duplicate children added: parent = Group@68887c42
    at javafx.scene.Parent$2.onProposedChange(Parent.java:454)
    at com.sun.javafx.collections.VetoableListDecorator$VetoableSubListDecorator.clear(VetoableListDecorator.java:529)
    at com.sun.javafx.binding.ContentBinding$ListContentBinding.onChanged(ContentBinding.java:114)
    at org.reactfx.collection.ChangeListenerWrapper.onChange(LiveList.java:439)
    at org.reactfx.collection.ChangeListenerWrapper.onChange(LiveList.java:417)
    at org.reactfx.util.ListNotifications.lambda$takeHead$0(NotificationAccumulator.java:317)
    at org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:68)
    at org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:57)
    at org.reactfx.collection.MappedList.sourceChanged(MappedList.java:41)
    at org.reactfx.collection.LiveList.lambda$observeQuasiChanges$7(LiveList.java:256)
    at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
    at test1.Main.start(Main.java:27)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:748)

I want that for each element in intList there will be a Circle in the group's children. Why does this happen and how can I make it work properly?

Mark
  • 2,167
  • 4
  • 32
  • 64

1 Answers1

-1

The exception description is a red herring - the message "duplicate children added" is given whenever at the end of the change the number of children doesn't match what the change predicted it to be.
In your case, what actually happens is that the circle is not removed, so the Group ends up with a single child, yet clear predicted it should have ended with 0.

The reason why the circle is not removed is that it is not the same circle - your mapper creates a new Circle object whenever it is asked to perform the mapping, and so you get 1 circle when adding it, and a completely different one when clearing the list - this new Circle cannot be removed from the children of the group, and so it remains with 1 child even after the call to clear, triggering the exception.

To solve this you would have to make sure you return the same target-object for the same source-object - this may not be possible if your list of integers may contain duplicates.

Itai
  • 6,641
  • 6
  • 27
  • 51
  • But the 2 circle are `equals()`, no? – Mordechai Dec 05 '17 at 16:20
  • Why would they be? – Itai Dec 05 '17 at 17:56
  • but why is the method called twice? – Mark Dec 05 '17 at 20:31
  • Is is called whenever someone tries to `get` an item from the `LiveList`, as it needs to translate the original item. The first is when you add, the second when you remove. – Itai Dec 05 '17 at 20:57
  • No. adding is called twice and removing is called twice. Look at the exception. Remove `intList.clear();` and see for yourself. – Mark Dec 06 '17 at 04:04
  • The exception only means the group ended up with the wrong amount of children after the change, which is the result of being unable to remove a node which wasn't there in the first place. The exception clearly pertains to the `clear` call, so removing it should also remove the exception. – Itai Dec 06 '17 at 07:12
  • Obviously the exception the result of `clear` but read what I'm writing. Why is each operation called twice? Just remove `clear` and explain that. – Mark Dec 06 '17 at 15:27