How to bind the position in a List to an attribute of that element?

给你一囗甜甜゛ 提交于 2019-12-14 01:45:40

问题


I have an ObservableList<MyElement> list = FXCollections.observableArrayList();

public class MyElement
{
  private IntegerProperty position;//with getter
  //[...]

  //somewhere in the constructor taking the list as argument
  position.bind(list.indexOf(this));
}

Now I'd like to bind MyElement.position to the actual position in the list i.e. if the position changes in the list (for instance drag and drop in the GUI or anything else) I want the position property to be updated automatically.

Is this possible? Can I make a bidirectional binding between these values?


回答1:


I don't know if I correctly understood your question, but I will try to answer it :-).

The thing is, once a ObservableList (javafx.collections) object does not store some kind of "selected" index state, why do we should bind another integer to it?

I think, in this case, your code should be responsible for store the "selected" index state and expose it to a client code. If this is what you are looking for, I suggest you have three attributes to deal with it:

public class ListSelection<T> {
    private ObservableList<T> items = FXCollections.observableArrayList(new ArrayList<T>());
    private ObjectProperty<T> selectedItem = new SimpleObjectProperty<>();
    private IntegerProperty selectedIndex = new SimpleIntegerProperty(0);
}

The selected element can be controlled using the selectedIndex attribute.

Then, create a bind to the selectedItem, to "automatically" update it when selectedIndex change:

selectedItem.bind(
    when(isEmpty(items))
        .then(new SimpleObjectProperty<T>())
        .otherwise(valueAt(items, selectedIndex))
);

Bindings should have been imported statically:

import static javafx.beans.binding.Bindings.*;

Notice the use of method Bindings.valueAt(ObservableList<E> list, ObservableIntegerValue index). It creates a bind to the list.get(index.getValue()) element.

Finally, you can use it like this:

ListSelection<String> selection = new ListSelection<>();
Label label = new Label();
List<String> weekDays = Arrays.asList("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday");

selection.getItems().addAll(weekDays);
label.textProperty().bind(selection.selectedItemProperty());

I also suggest you to take a look to javafx.scene.control.SelectionModel class and its subclasses (eg. javafx.scene.control.SingleSelectionModel). Maybe, it could be easier to extend some of them.




回答2:


I don't have a bidirectional binding but if you only want the property to be updated when the position changes in the list, you can use this code:

import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;

/**
 * An integer property that's bound to the index of an item in an observable list. For example, if your list
 * is ["car", "train", "ship"], then new PositionInListProperty("train", list) will be 1. The binding is unidirectional.
 * Changing this property doesn't affect the list.
 *
 * @param <T> Type of elements in the list.
 */
public class PositionInListProperty<T> extends SimpleIntegerProperty implements ListChangeListener<T> {
    private final T item;
    private final ObservableList<T> list;

    /**
     * Creates the property and binds it to an observable list.
     * @param item The position of this item in the list is tracked by this property.
     * @param list Whenever this list changes, the value of this property is updated.
     */
    public PositionInListProperty(T item, ObservableList<T> list) {
        this.item = item;
        this.list = list;
        this.setValue(list.indexOf(item));
        list.addListener(this);
    }

    @Override
    public void onChanged(Change<? extends T> c) {
        this.setValue(list.indexOf(item));
    }

It adds itself as a listener to the list and reacts on all events. You can then use the property (read-only!) as normal. The time complexity of indexOf is O(n), though, so if you have a long list, you'll want to somehow optimize this.



来源:https://stackoverflow.com/questions/16217814/how-to-bind-the-position-in-a-list-to-an-attribute-of-that-element

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!