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 rowreturn 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);}@Overridepublic 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();}
}
运行结果: