![](/img/trans.png)
[英]Proper way to bind a Property to a Value derived from a control in JavaFx / TornadoFX
[英]handle derived property in JavaFX
我現在正在使用JavaFX,並且正在關注一個教程來學習Java的這一領域。 我對屬性有疑問:
如何正確處理JavaFX中的派生屬性?
讓我用一個例子來闡明。 假設您有一個具有簡單屬性的模型:
public class User {
private final StringProperty name;
private final ObjectProperty<LocalDate> birthday;
}
(我忽略了構造函數和屬性getter:假設它們在那里),並假設您有一個帶有TableView的視圖,其中有2列列出了用戶,其中:
這樣的事情(還顯示一些繪畫技巧!):
現在,年齡當然是生日字段的派生屬性,可以通過以下方法輕松實現:
public int getAge() {
return Period.between(this.getBirthday().get(), LocalDate.now()).getYears();
}
但是,表視圖將不接受整數,而僅接受可觀察的整數。 如果有人更改用戶的生日,我希望表格自動更改。
我可以創建一個SimpleIntegerProperty
里面setCellValueFactory
,但我不認為這可能是一個解決方案。 我還可以在User
類中創建一個名為age
的IntegerProperty
但聽起來不對,因為age是生日的派生屬性 。
所以這引起了我的問題:如何處理JavaFX中的派生屬性?
PS:我看了這個SO答案,但是,可能由於我在該領域的專業知識,我無法令人滿意。
感謝您的任何答復。
您可以使用提到的setCellValueFactory
和SimpleIntegerProperty
來做到這SimpleIntegerProperty
:
TableColumn<User, Integer> ageCol = new TableColumn<User, Integer>("Age");
ageCol.setCellValueFactory(param -> {
SimpleIntegerProperty prop = new SimpleIntegerProperty(param.getValue().getAge());
prop.bind(Bindings.createIntegerBinding(() -> {
return param.getValue().getAge();
}, param.getValue().birthday));
return prop.asObject();
});
但是,在創建綁定時,請使用以下依賴項param.getValue().birthday
,這是您知道getAge()
方法的內部計算的標記(好的,對於這種情況,很明顯,計算基於生日,但在某些情況下並非如此)。
因此,我將選擇您提到的第二個選項,將計算封裝到它所屬的位置: User
類中的另一個(只讀)屬性,其中年齡與生日綁定。
public static class User {
private final StringProperty name;
private final ObjectProperty<LocalDate> birthday;
private final ReadOnlyIntegerWrapper age;
public StringProperty nameProperty() { return name; }
public ObjectProperty<LocalDate> birthdayProperty() { return birthday; }
public ReadOnlyIntegerProperty ageProperty() { return age.getReadOnlyProperty(); }
private User(String name, LocalDate bDay) {
this.name = new SimpleStringProperty(name);
birthday = new SimpleObjectProperty<LocalDate>(bDay);
this.age = new ReadOnlyIntegerWrapper();
age.bind(Bindings.createIntegerBinding(() -> Period.between(this.getBirthday(), LocalDate.now()).getYears(), birthday));
}
public String getName() { return name.get(); }
public LocalDate getBirthday() { return birthday.get(); }
public int getAge() { return ageProperty().get(); }
}
然后使用它:
TableColumn<User, Integer> ageCol = new TableColumn<User, Integer>("Age");
ageCol.setCellValueFactory(new PropertyValueFactory<User, Integer>("age"));
該示例使用ReadOnlyIntegerWrapper
(根據您鏈接的答案),並通過ReadOnlyIntegerProperty
公開內部屬性的age
:
public ReadOnlyIntegerProperty ageProperty() { return age.getReadOnlyProperty(); }
更新:在age
屬性上使用延遲初始化的同一User
類。
public static class User {
private final StringProperty name;
private final ObjectProperty<LocalDate> birthday;
private ReadOnlyIntegerWrapper age = null;
public StringProperty nameProperty() { return name; }
public ObjectProperty<LocalDate> birthdayProperty() { return birthday; }
public ReadOnlyIntegerProperty ageProperty() {
if (age == null) {
age = new ReadOnlyIntegerWrapper();
age.bind(Bindings.createIntegerBinding(() -> calculateAge(), birthday));
}
return age.getReadOnlyProperty();
}
private User(String name, LocalDate bDay) {
this.name = new SimpleStringProperty(name);
birthday = new SimpleObjectProperty<LocalDate>(bDay);
}
public String getName() { return name.get(); }
public LocalDate getBirthday() {return birthday.get(); }
public int getAge() {
return (age != null) ? age.get() : calculateAge();
}
private final int calculateAge() {
return Period.between(this.getBirthday(), LocalDate.now()).getYears();
}
}
您可以公開DoubleBinding
而不是年齡的屬性。 DoubleBinding
是ObservableValue<Number>
的實現(因此可以由cellValueFactory
的回調返回),但是與DoubleProperty
或ReadOnlyDoubleProperty
它不內部存儲其值:
public class User {
private final ObjectProperty<LocalDate> birthday ;
public ObjectProperty<LocalDate> birthdayProperty() {
return birthday ;
}
public final LocalDate getBirthday() {
return birthdayProperty().get();
}
public final void setBirthday(LocalDate birthday) {
birthdayProperty().set(birthday);
}
private final DoubleBinding age = Bindings.createDoubleBinding(
() -> Period.between(this.getBirthday(), LocalDate.now()).getYears(),
birthday);
public DoubleBinding age() {
return age ;
}
}
然后您可以做類似的事情
TableColumn<User, Number> ageColumn = new TableColumn<>(age);
ageColumn.setCellValueFactory(cellData -> cellData.getValue().age());
請注意,此示例並非真正理想,因為age
可以更改值,而birthday
不會更改值(由於時間的推移具有不可抑制的性質...)。 因此,要使其真正准確,您可能需要ObjectProperty<LocalDate> today
某個地方創建一個ObjectProperty<LocalDate> today
,並每天進行更新。 然后,在更改age
限制時也進行更新
private final DoubleBinding age = Bindings.createDoubleBinding(
() -> Period.between(this.getBirthday(), LocalDate.now()).getYears(),
birthday, today);
盡管原始版本可能足以滿足大多數實際用例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.