PropertyValueFactory类是“TableColumn cell value factory”,绑定创建列表中的项。示例如下:
TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name");
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName"));
在以上中,Person类是TableView项目列表的项(items),Person类必须是public,“First Name”是在TableView中显示的表头内容。PropertyValueFactory类使用构造方法传入的参数“firstName”在Person类中寻找与firstName对应的无参属性方法firstNameProperty返回ObservableValue<String>。
如果无参属性方法firstNameProperty存在,则该方法会被触发并返回一个Property<String>类型的实例。返回的实例作为数据项用来填充“Table Cell”。同时,TableView给返回的Property<String>实例注册一个观察者(observer),这样对数据项的任何改变都因触发observer立即通知TableView,项内容立即更新。
如果Person类中没有无参属性方法firstNameProperty,PropertyValueFactory类则会扫描Person类中是否有返回值是String类型的无参方法getFirstName或无参方法isFirstName。如果有以上方法,则该方法会被调用,返回被ReadOnlyObjectWrapper包装的值,值填充“Table Cell”。这种情况下,TableCell无法给包装的属性注册观察者观察数据变化状态。这种情况与调用属性方法firstNameProperty不同。
For reference (and as noted in the TableColumn TableColumn.cellValueFactoryProperty()
cell value factory} documentation), the long form of the code above would be the following:
以下代码作为参考:
TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name");
firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<Person, String> p) {
// p.getValue() returns the Person instance for a particular TableView row
return p.getValue().firstNameProperty();
}
});
}
以下是一个使用PropertyValueFactory的例子:
继承PropertyValueFactory的类,实现方法call:
package cn.learnjavafx.ch13.tableview04;
import java.time.LocalDate;
import static java.time.temporal.ChronoUnit.YEARS;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.cell.PropertyValueFactory;
import cn.learnjavafx.ch11.Person;
/**
* @copyright 2023-2022
* @package cn.learnjavafx.ch13.tableview04
* @file CallbackData.java
* @date 2023-07-08 22:59
* @author qiao wei
* @version 1.0
* @brief
* @history
*/
public class CallbackData extends PropertyValueFactory<Person, String> {
public CallbackData(Person person, String content) {
super(content);
}
@Override
public ObservableValue<String> call(CellDataFeatures<Person, String> cellDataFeatures) {
Person person = cellDataFeatures.getValue();
LocalDate localDate = person.getBirthDate();
String ageInYear = "Unknown";
if (null != localDate) {
long years = YEARS.between(localDate, LocalDate.now());
if (years == 0) {
ageInYear = "< 1 year";
} else if (years == 1) {
ageInYear = years + " year";
} else {
ageInYear = years + " years";
}
}
return new ReadOnlyStringWrapper(ageInYear);
}
}
package cn.learnjavafx.ch13.tableview04;
import java.time.LocalDate;
import static java.time.temporal.ChronoUnit.YEARS;
import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import cn.learnjavafx.ch11.AgeCategory;
import cn.learnjavafx.ch11.Person;
import cn.learnjavafx.ch13.PersonTableUtil;
public class TableViewDataTest extends Application {
public static void main(String[] args) {
Application.launch(TableViewDataTest.class, args);
}
@Override
// @SuppressWarnings("unchecked")
public void start(Stage primaryStage) {
// Create a TableView and bind model.
TableView<Person> table = new TableView<>(PersonTableUtil.getPersonList());
/**
* Create an "Age" computed column.
* TableColumn<S, T>(text)
* S: The type of the TableView generic type.
* T: The type of the content in all cells in this TableColumn.
* text: The string to show when the TableColumn is placed within the TableView.
*/
TableColumn<Person, String> ageColumn = new TableColumn<>("Age");
// ageColumn.setCellValueFactory(cellData -> {
// Person person = cellData.getValue();
// LocalDate localDate = person.getBirthDate();
// String ageInYear = "Unknown";
//
// if (null != localDate) {
// long years = YEARS.between(localDate, LocalDate.now());
// if (years == 0) {
// ageInYear = "< 1 year";
// } else if (years == 1) {
// ageInYear = years + " year";
// } else {
// ageInYear = years + " years";
// }
// }
//
// return new ReadOnlyStringWrapper(ageInYear);
// });
ageColumn.setCellValueFactory(new CallbackData(new Person(), new String()));
// Create an "Age Cotegory" column.
TableColumn<Person, AgeCategory> ageCategoryColumn = new TableColumn<>("Age Category");
ageCategoryColumn.setCellValueFactory(new PropertyValueFactory<>("AgeCategory"));
// Add columns to the TableView.
table.getColumns().addAll(PersonTableUtil.getIdColumn()
, PersonTableUtil.getFirstNameColumn()
, PersonTableUtil.getLastNameColumn()
, PersonTableUtil.getBirthDateColumn()
, ageColumn
, ageCategoryColumn);
HBox root = new HBox(table);
root.setStyle("-fx-padding: 10;"
+ "-fx-border-style: solid inside;"
+ "-fx-border-width: 2;"
+ "-fx-border-insets: 5;"
+ "-fx-border-radius: 5;"
+ "-fx-border-color: blue;");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Populating TableViews");
primaryStage.show();
}
}
运行结果: