2015-10-02 64 views
0

我有一個經典的JavaBean,它將與JavaFX TextField綁定。Javafx中的雙向綁定StringProperty不能反向工作

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)); 
    } 

} 

另外我創建了一個字符串轉換子類:

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); 
    } 


} 

在控制器類,前主級變得可見,我發細胞值和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。當我輸入一個值(比方說,「4」)在一個空的文本字段,這些信息將顯示:

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

如果鍵入「8」,在此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 

最後,如果我輸入「0」,單元格將變爲空:

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

到目前爲止,這麼好。但是,如果雙擊TextField,而不是替換文本,則什麼都不會發生。假設單元格的值(和texfField)爲4。當我雙擊,我得到這個消息:

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

然而,文本框會繼續帶出「4」。未顯示CellValueStringConverter.toString()中的消息。

假設,當我將單元格值包裝在ObjectPropertyJavaBeanObjectPropertyBuilder.create().bean(cell).name("value").build())中時,它應該觀察值屬性中的所有更改。但是沒有發生。這裏缺少什麼?

感謝,

拉斐爾·阿豐索

回答

0

我想我找到了答案,或至少一種解決方法。我有當Cell.value attibute更改爲新PropertyChangeEvent添加到我的Cell對象的是,valueProperty直接設置好的:

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

至少,事情開始按預期運行。當我加倍ciclk了一個空的文本字段,我得到的消息:

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

和預期的文本字段被填滿。不過,我覺得奇怪的是,valueProperty消息是最後打印的,儘管他的setter是第一個被調用的東西。

如果有人有更好的主意,這將是受歡迎的。