Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible in JavaFX to modify the dependencies of a binding after it's created?

My question arose when implementing some sorts of graph visualization with JavaFX. There are 2 classes called Vertex and Edge, with each edge connecting 2 (possibly the same) vertices. Every vertex that has self-loops (edges having the same start and end vertices) stores a DoubleProperty for the preferred angle of its self-loops. This angle is computed from the the positions of this vertex and all its neighbors. However, as the graph is constructed dynamically, neighbors of a vertex may change, resulting in a dynamic list of dependencies, so I have to modify the dependendies of the DoubleBinding to which the angle is bound.

However, the getDependencies method in the DoubleBinding created by Bindings.createDoubleBinding only returns an immutable copy:

@Override
public ObservableList<?> getDependencies() {
    return  ((dependencies == null) || (dependencies.length == 0))?
                FXCollections.emptyObservableList()
            : (dependencies.length == 1)?
                FXCollections.singletonObservableList(dependencies[0])
            : new ImmutableObservableList<Observable>(dependencies);
}

And although the DoubleBinding class has an bind method that seems to satisfy my need, it is protected:

protected final void bind(Observable... dependencies) {
    if ((dependencies != null) && (dependencies.length > 0)) {
        if (observer == null) {
            observer = new BindingHelperObserver(this);
        }
        for (final Observable dep : dependencies) {
            dep.addListener(observer);
        }
    }
}

So is there any way that I can modify the dependencies at any time without defining my own DoubleBinding, or can I solve my problem without touching the dependencies?

like image 892
CirF Avatar asked Oct 31 '25 06:10

CirF


1 Answers

You can bind your DoubleProperty to an ObservableList containing the neighbor nodes. This way the binding will be invalidated if anything is added to or removed from the list. Here's a very quick demo of the idea:

import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class BindingDemo {

    public static void main(String[] args) {
        ObservableList<GraphNode> neighbors = FXCollections.observableArrayList();
        IntegerProperty total = new SimpleIntegerProperty();
        total.bind(Bindings.createIntegerBinding(
                () -> sum(neighbors),
                neighbors
        ));
        total.addListener((obs, oldTotal, newTotal) -> 
                System.out.println("Total = "+newTotal));
        for (int i = 1 ; i <= 5 ; i++) {
            System.out.println("Adding node with value "+i+":");
            neighbors.add(new GraphNode(i));
        }
    }

    private static int sum(ObservableList<GraphNode> nodes) {
        int total = 0 ;
        for (GraphNode node : nodes) {
            total += node.value();
        }
        return total ;
    }

    public static record GraphNode(int value){}
}

Output:

Adding node with value 1:
Total = 1
Adding node with value 2:
Total = 3
Adding node with value 3:
Total = 6
Adding node with value 4:
Total = 10
Adding node with value 5:
Total = 15

Technically, this doesn't really avoid your "without defining my own binding" requirement, but the Bindings.createXXXBinding(...) API makes it pretty clean to do so.

like image 64
James_D Avatar answered Nov 02 '25 21:11

James_D