Javafx StringProperty中的双向绑定不能反向运行

时间:2015-10-02 00:57:40

标签: binding javafx

我有一个经典的JavaBean,它将与JavaFX TextField绑定。

public class Cell {

    public static final String CELL_VALUE = "Cell.Value";

    private Optional<Integer> value;

    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);


    public Optional<Integer> getValue() {
        return value;
    }

    public void setValue(Optional<Integer> value) {
        Optional<Integer> old = this.value;
        this.value = value;
        this.pcs.firePropertyChange(CELL_VALUE, old, value);
    }

    /**
     * The values must be from 1 to 9. 0 or null will be converted to Option.none.
     */
    public void setValue(int value) {
        this.setValue(Optional.of(value));
    }

}

我还创建了一个StringConverter子类:

import java.util.Optional;
import javafx.util.StringConverter;

public class CellValueStringConverter extends StringConverter<Optional<Integer>> {

    @Override
    public String toString(Optional<Integer> value) {
        System.out.printf("toString()   : %s%n", value);
        return value.isPresent()? String.valueOf(value.get()): "";
    }

    @Override
    public Optional<Integer> fromString(String string) {
        System.out.printf("fromString() : %s%n", string);
        if(string.matches("^[1-9]$")) {
            return Optional.of(Integer.valueOf(string));
        }
        if(string.isEmpty() || string.matches("^( |0)$")) {
            return Optional.empty();
        }

        throw new IllegalArgumentException("Illegal value for a Cell: " + string);
    }


}

在控制器类中,在主舞台可见之前,我在Cell值和TextField之间进行了绑定:

ObjectProperty<Optional<Integer>> valueProperty = JavaBeanObjectPropertyBuilder.create().bean(cell)
        .name("value").build();
final StringProperty textProperty = textField.textProperty();
// Binding ...
textProperty.bindBidirectional(valueProperty, new CellValueStringConverter());

textField.addEventFilter(MouseEvent.MOUSE_CLICKED, me -> {
    if (me.getClickCount() == 2) {
        cell.setValue(random.nextInt(8) + 1);
    }
});

        textProperty.addListener(
                (ov, oldValue, newValue) -> System.out.printf("textProperty : %s -> %s%n", oldValue, newValue));
        valueProperty.addListener(
                (ov, oldValue, newValue) -> System.out.printf("valueProperty: %s -> %s%n", oldValue, newValue));
        cell.addPropertyChangeListener(
                evt -> System.out.printf("cell         : %s -> %s%n", evt.getOldValue(), evt.getNewValue()));

当我启动应用程序时,收到消息toString() : Optional.empty。当我在空的TextField中键入一个值(让我们说&#34; 4&#34;)时,会打印这些消息:

fromString() : 4
cell         : Optional.empty -> Optional[4]
valueProperty: Optional.empty -> Optional[4]
textProperty :  -> 4

如果我输入&#34; 8&#34;在这个TextField中我得到了这个:

fromString() : 
cell         : Optional[4] -> Optional.empty
valueProperty: Optional[4] -> Optional.empty
textProperty : 4 -> 
fromString() : 8
cell         : Optional.empty -> Optional[8]
valueProperty: Optional.empty -> Optional[8]
textProperty :  -> 8

最后,如果我输入&#34; 0&#34;,则Cell将变为空:

fromString() : 
cell         : Optional[8] -> Optional.empty
valueProperty: Optional[8] -> Optional.empty
textProperty : 8 -> 

到目前为止,这么好。但是,如果双击TextField,而不是替换文本,则没有任何反应。假设单元格值(和texfField)是4.当我双击时,我收到此消息:

cell         : Optional[4] -> Optional[8]

然而textField继续显示&#34; 4&#34;。 CellValueStringConverter.toString()中的消息未显示。

据说,当我将单元格值包装在ObjectPropertyJavaBeanObjectPropertyBuilder.create().bean(cell).name("value").build())中时,它应该观察value属性中的所有更改。但是没有发生。这里缺少什么?

谢谢,

Rafael Afonso

1 个答案:

答案 0 :(得分:0)

我认为我找到了答案或至少是一种解决方法。我必须向我的PropertyChangeEvent对象添加一个新的Cell,以便更改Cell.value属性时,会直接设置valueProperty:

cell.addPropertyChangeListener(evt -> {
    @SuppressWarnings("unchecked")
    final Optional<Integer> newValue = (Optional<Integer>) evt.getNewValue();
    valueProperty.set(newValue);
});

至少,事情开始按预期发挥作用。当我在一个空的TextField上加倍ciclk时,我得到这些消息:

cell         : Optional.empty -> Optional[2]
toString()   : Optional[2]
textProperty :  -> 2
valueProperty: Optional.empty -> Optional[2]

textField按预期填充。但是,我觉得奇怪的是,valueProperty消息是最后打印的,尽管他的setter是第一个被调用的东西。

如果有人有更好的想法,那将是受欢迎的。