绑定到可以切换的对象的JavaFX属性

edolor 发布于 2019-03-15 最后更新 2019-03-15 14:53 5 浏览

绑定到属性本身包装在属性中的属性看起来像是在典型应用程序中做了很多事情,在JavaFX中执行此操作的方法是否比我在下面做的更好? 一些更详细的解释:我想在JavaFX 2.2中制作GUI,以管理多个项目。我创建了一个小例子来测试所有项目都是人的东西。这组人以自定义的方式显示(不是列表或树,但我认为这不重要),我可以选择一个。 在侧面板中,我可以编辑当前选定的人员。更新在人员集合中立即可见,并且当我选择另一个人时,编辑面板将被更新。 JavaFX的双向绑定似乎是完美的。我目前对“人物编辑”窗格的fx:controller有这个功能:

public class PersonEditor implements ChangeListener<Person> {
    @FXML private TextField nameField;
    @FXML private TextField ageField;
    @FXML private TextField heightField;
public void setSelection(ObjectProperty<Person> selectedPersonProperty) {
        selectedPersonProperty.addListener(this);
    }
@Override
    public void changed(ObservableValue<? extends Person> observable, Person oldVal, Person newVal) {
        if (oldVal != null) {
            nameField.textProperty().unbindBidirectional(oldVal.nameProperty());
            ageField.textProperty().unbindBidirectional(oldVal.ageProperty());
            heightField.textProperty().unbindBidirectional(oldVal.heightProperty());
        }
        if (newVal != null) {
            nameField.textProperty().bindBidirectional(newVal.nameProperty());
            ageField.textProperty().bindBidirectional(newVal.ageProperty());
            heightField.textProperty().bindBidirectional(newVal.heightProperty());
        }
    }
}
我想知道是否有更好的方法,也许在JavaFX中绑定到可以更改的对象的属性?我不喜欢我必须手动取消绑定所有属性的事实,它感觉像重复的代码。 或者,这是否像在JavaFx中那样简单?
已邀请:

zex

赞同来自:

就个人而言,我没有发现你在事件处理程序中编写的代码是那些笨拙或笨拙的代码。这是事件处理程序通常在GUI,imo中执行的操作。 问问自己,虽然......在你的环境中真的有必要吗? 如果您必须对在一个面板中进行的编辑进行实时更新以反映在另一个面板中,那么您可能已经实现了最简单的解决方案。然而,这种UI设计存在固有的困难,并且它可能不是所有情况下的最佳选择。如果用户需要取消他所做的编辑怎么办?如果他改变主意,你有办法回滚编辑吗?有时,编辑的实时更改是不可取的,在这种情况下,将数据模型对象绑定到UI对象可能不是一个好主意。

fomnis

赞同来自:

看起来这不是可以在JavaFX中更优雅地完成的事情。绑定和解除绑定似乎是最干净的方式。 我自己实现了一种方法来实现这一点。不确定我是否最终会使用它(因为它只是用难以阅读的代码替换代码重复)。但它有效,它是我自己的问题的答案,所以我在这里添加它。 新的PersonEditor类:

public class PersonEditor implements Initializable {
    private SelectedObjectPropertyBinder<Person> selectedObjectPropertyBinder = 
          new SelectedObjectPropertyBinder<Person>();
@FXML private TextField nameField;
    @FXML private TextField ageField;
    @FXML private TextField heightField;
@Override
    public void initialize(URL url, ResourceBundle rb) {
        selectedObjectPropertyBinder.getBinders().add(
            new ObjectPropertyBindHelper<Person>(nameField.textProperty()) {
                @Override public Property objectProperty(Person p) 
                { return p.nameProperty(); }
        });
        selectedObjectPropertyBinder.getBinders().add(
            new ObjectPropertyBindHelper<Person>(ageField.textProperty()) {
                @Override public Property objectProperty(Person p) 
                { return p.ageProperty(); }
        });
        selectedObjectPropertyBinder.getBinders().add(
            new ObjectPropertyBindHelper<Person>(heightField.textProperty()) {
                @Override public Property objectProperty(Person p) 
                { return p.heightProperty(); }
        });
    }
public void setSelection(ObjectProperty<Person> selectedPersonProperty) {
        selectedObjectPropertyBinder.
            setSelectedObjectProperty(selectedPersonProperty);
    }
}
助手类:
public class SelectedObjectPropertyBinder<T> implements ChangeListener<T> {
    private List<ObjectPropertyBindHelper<T>> binders = 
           new ArrayList<ObjectPropertyBindHelper<T>>();
public void setSelectedObjectProperty(Property<T> selectionProperty) {
        selectionProperty.addListener(this);
    }
public List<ObjectPropertyBindHelper<T>> getBinders() {
        return binders;
    }
@Override
    public void changed(ObservableValue<? extends T> observable, 
                        T oldVal, T newVal) {
        if (oldVal != null)
            for (ObjectPropertyBindHelper b : binders)
                b.unbindBi(oldVal);
        if (newVal != null)
            for (ObjectPropertyBindHelper b : binders)
                b.bindBi(newVal);
    }
}
public abstract class ObjectPropertyBindHelper<T> {
    private Property boundProperty;
public ObjectPropertyBindHelper(Property boundProperty) {
        this.boundProperty = boundProperty;
    }
    public void bindBi(T o) {
        boundProperty.bindBidirectional(objectProperty(o));
    }
    public void unbindBi(T o) {
        boundProperty.unbindBidirectional(objectProperty(o));
    }
    public abstract Property objectProperty(T t);
    public Property getBoundProperty() {
        return boundProperty;
    }
}
正如斯科特在他的回答中指出的那样,绑定链接并不总是你想要的。如果你想要能够取消/提交更改,你也可以使用类似的东西来实现它(但是读取结果代码可能会更难)。