这篇文章是关于如何处理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());
}
@Override
protected 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存储库中找到完整的代码。