簡體   English   中英

處理JavaFX中的派生屬性

[英]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類中創建一個名為ageIntegerProperty但聽起來不對,因為age是生日的派生屬性

所以這引起了我的問題:如何處理JavaFX中的派生屬性?

PS:我看了這個SO答案,但是,可能由於我在該領域的專業知識,我無法令人滿意。

感謝您的任何答復。

您可以使用提到的setCellValueFactorySimpleIntegerProperty來做到這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而不是年齡的屬性。 DoubleBindingObservableValue<Number>的實現(因此可以由cellValueFactory的回調返回),但是與DoublePropertyReadOnlyDoubleProperty它不內部存儲其值:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM