我有一个经典的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()
中的消息未显示。
据说,当我将单元格值包装在ObjectProperty
(JavaBeanObjectPropertyBuilder.create().bean(cell).name("value").build()
)中时,它应该观察value属性中的所有更改。但是没有发生。这里缺少什么?
谢谢,
Rafael Afonso
答案 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是第一个被调用的东西。
如果有人有更好的想法,那将是受欢迎的。