这篇文章是关于如何处理JavaFX ListViews和TableViews的,以及这些控件如何得知所包含元素的更改内容。 我想知道为什么在相关书籍中没有找到关于以下模式的任何信息,因为这是一个非常关键的机制。 那里的许多帖子建议通过调用以下命令来强制触发ChangeEvent以刷新ListView:
list.remove(POJO);
list.add(index,POJO);
每次提交更改后! rr!
但是有更好的方法:
通过提供属性提取器,使列表能够报告元素上的更改。
演示应用
我创建了一个小型演示应用程序,可以尝试一下。 基本上两个TableViews和一个ListView都共享相同的数据。 要更改元素的属性,一个TableView是可编辑的:
数据模型
强制性PersonBean遵循JavaFX Bean Pattern / Convention
public class PersonBean {private StringProperty firstName;private StringProperty lastName;private ObjectProperty<LocalDate> birthday;private ObjectBinding<Long> age;public PersonBean() {}public PersonBean(String firstName, String lastName, LocalDate birthday) {setFirstName(firstName);setLastName(lastName);setBirthday(birthday);}public final StringProperty firstNameProperty() {if (firstName == null) {firstName = new SimpleStringProperty();}return firstName;}public final String getFirstName() {return firstNameProperty().get();}public final void setFirstName(final java.lang.String firstName) {firstNameProperty().set(firstName);}public final StringProperty lastNameProperty() {if (lastName == null) {lastName = new SimpleStringProperty();}return lastName;}public final java.lang.String getLastName() {return lastNameProperty().get();}public final void setLastName(final java.lang.String lastName) {lastNameProperty().set(lastName);}public final ObjectProperty<LocalDate> birthdayProperty() {if (birthday == null) {birthday = new SimpleObjectProperty<>();}return birthday;}public final LocalDate getBirthday() {return birthdayProperty().get();}public final void setBirthday(final java.time.LocalDate birthday) {birthdayProperty().set(birthday);}public String stringValue() {return String.format("%s %s %s", getFirstName(), getLastName(), getBirthday().format(DateTimeFormatter.ISO_LOCAL_DATE));}public final ObjectBinding<Long> ageBinding() {if (age == null) {age = new ObjectBinding<Long>() {{bind(birthdayProperty());}@Overrideprotected Long computeValue() {if (getBirthday() == null) {return null;}return getBirthday().until(LocalDate.now(), ChronoUnit.YEARS);}};}return age;}public static Callback<PersonBean, Observable[]> extractor() {return (PersonBean p) -> new Observable[]{p.lastNameProperty(), p.firstNameProperty(), p.birthdayProperty(), p.ageBinding()};}
}
包含随机创建的PersonBeans列表的DataModel:
public class DataModel {private ObservableList<PersonBean> personFXBeans;public DataModel() {init();}private void init() {personFXBeans = DataSource.getRandomPersonBeansList(100);}public ObservableList<PersonBean> getPersonFXBeans() {return personFXBeans;}
}
您可能知道将DataModel例如分配给JavaFX中的TableView或ListView,您只需要使用setItems(ObvervableList)方法。
@FXML
public void onFillWithDemoDataFXBeans() {readOnlyListView.setItems(model.getPersonFXBeans());readOnlyTableView.setItems(model.getPersonFXBeans());editableTableView.setItems(model.getPersonFXBeans());
}
现在已经通过两种方式通过绑定完成了TableView的有关所包含元素的属性更改的通知:通过PropertyValueFactory
或通过或多或少的直接属性绑定:
readOnlyFirstNameColumn.setCellValueFactory(new PropertyValueFactory<>("firstName"));
readOnlyLastNameColumn.setCellValueFactory(new PropertyValueFactory<>("lastName"));
readOnlyBirthdayColumn.setCellValueFactory(new PropertyValueFactory<>("birthday"));
readOnlyAgeColumn.setCellValueFactory(i -> i.getValue().ageBinding());editableFirstNameColumn.setCellValueFactory(i -> i.getValue().firstNameProperty());
editableLastNameColumn.setCellValueFactory(i -> i.getValue().lastNameProperty());
editableBirthdayColumn.setCellValueFactory(i -> i.getValue().birthdayProperty());
ageColumn.setCellValueFactory(i -> i.getValue().ageBinding());
但是ListView基本上只观察列表,而不观察列表中每个元素的属性。
当使用由FXCollections.observableArrayList()创建的ObservableList时,ListView将仅在ListChange事件上刷新,例如remove()元素的add()。 因此:
list.remove(POJO);
list.add(index,POJO);
每次提交更改后。
但是有更好的方法:
通过提供属性提取器,使列表能够报告元素上的更改。 那您就不必担心刷新了!
ObservableList person = FXCollections.observableArrayList( PersonBean.extractor() );
请参见DataSource.getRandomPersonBeansList(int length)
:
public static ObservableList<PersonBean> getRandomPersonBeansList(int length) {ObservableList<PersonBean> persons = FXCollections.observableArrayList(PersonBean.extractor());for (int i = 0; i < length; i++) {persons.add(new PersonBean(getRandomName(), getRandomLastname(), getRandomLocalDate()));}return persons;}
此Extrator基本上是一个回调,其中包含一个Obvervable数组,然后由Obervablelist观察(更精确的是:ObservableListWrapper):
我的PersonBean
已经提供了Extrator回调:
public static Callback<PersonBean, Observable[]> extractor() {return (PersonBean p) -> new Observable[]{p.lastNameProperty(), p.firstNameProperty(), p.birthdayProperty(), p.ageBinding()};
}
按照此模式,所有控件在应用更改后都会立即更新。
编辑资料...
并提交:
请输入密码!
您可以在我的BitBucket存储库中找到完整的代码。
翻译自: https://www.javacodegeeks.com/2014/11/properties-extractor-best-way-to-get-the-listview-instantly-updating-its-elements.html