如何为 TableColumn 设置 CellValueFactory 以允许访问整个对象?
How to set CellValueFactory for TableColumn to allow access to entire object?
我有一个简单的 Person
对象列表,我正在使用 TableView
来显示:
class Person {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty emailAddress = new SimpleStringProperty();
private final StringProperty phoneNumber = new SimpleStringProperty();
public Person(String name, String emailAddress, String phoneNumber) {
this.name.set(name);
this.emailAddress.set(emailAddress);
this.phoneNumber.set(phoneNumber);
}
}
我在这个例子中的目标是在同一个 TableColumn
中同时显示 emailAddress
和 phoneNumber
。这不仅仅是简单地连接值,因为我正在为此专栏实现自定义 TableCell
(实际应用程序更复杂):
private TableCell<Person, Person> buildContactCell() {
return new TableCell<Person, Person>() {
final VBox root = new VBox();
final Label lblEmailAddress = new Label();
final Label lblPhoneNumber = new Label();
{
root.getChildren().addAll(lblEmailAddress, lblPhoneNumber);
}
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (person != null && !empty) {
lblEmailAddress.setText(person.getEmailAddress());
lblPhoneNumber.setText(person.getPhoneNumber());
setGraphic(root);
} else {
setGraphic(null);
}
}
};
}
我假设这工作正常,但我不确定如何为这个 TableColumn
配置 CellValueFactory
以接受整个 Person
对象。
是否有另一种方法可以设置 TableCell
以访问 Person
中的多个 属性?我在实现多个属性时看到的其他问题只涉及连接,这不是我要找的。
完整代码:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TableCellSample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
root.getChildren().add(getTableView());
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
private TableView<Person> getTableView() {
TableView<Person> tableView = new TableView<>();
TableColumn<Person, String> colName = new TableColumn<>("Name");
colName.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
TableColumn<Person, Person> colContact = new TableColumn<>("Contact");
colContact.setCellFactory(cell -> buildContactCell());
// **********************************************************************************************
// Need to set the CellValueFactory for colContact here
// **********************************************************************************************
tableView.getColumns().addAll(colName, colContact);
tableView.setItems(getSampleData());
return tableView;
}
private TableCell<Person, Person> buildContactCell() {
return new TableCell<Person, Person>() {
final VBox root = new VBox();
final Label lblEmailAddress = new Label();
final Label lblPhoneNumber = new Label();
{
root.getChildren().addAll(lblEmailAddress, lblPhoneNumber);
}
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (person != null && !empty) {
lblEmailAddress.setText(person.getEmailAddress());
lblPhoneNumber.setText(person.getPhoneNumber());
setGraphic(root);
} else {
setGraphic(null);
}
}
};
}
private ObservableList<Person> getSampleData() {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.addAll(
new Person("Jack", "jack@outlook.com", "123-456-7890"),
new Person("Jenny", "goodtime@yahoo.com", "555-867-5309"),
new Person("Jesse", "mygirl@hotmail.com", "846-989-9988"));
return persons;
}
}
class Person {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty emailAddress = new SimpleStringProperty();
private final StringProperty phoneNumber = new SimpleStringProperty();
public Person(String name, String emailAddress, String phoneNumber) {
this.name.set(name);
this.emailAddress.set(emailAddress);
this.phoneNumber.set(phoneNumber);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public String getEmailAddress() {
return emailAddress.get();
}
public StringProperty emailAddressProperty() {
return emailAddress;
}
public String getPhoneNumber() {
return phoneNumber.get();
}
public StringProperty phoneNumberProperty() {
return phoneNumber;
}
}
您的单元格值工厂需要 return 一个包含行元素的 ObjectProperty<Person>
。您可以在单元格值工厂中使用 cellData.getValue()
获取行数据,其中 cellData
是传递给 call()
方法的参数。所以:
colContact.setCellValueFactory(cellData ->
new SimpleObjectProperty<>(cellData.getValue()));
模型应该真正满足视图的需要,让 TableCell 在幕后窥视整个 TableModel 是一种代码味道。组织模型可能更好,这样数据就可以直接用于 TableCell。尝试组合,像这样:
public class TableCellSample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
root.getChildren().add(getTableView());
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
private TableView<Person> getTableView() {
TableView<Person> tableView = new TableView<>();
TableColumn<Person, String> colName = new TableColumn<>("Name");
colName.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
TableColumn<Person, ContactInfo> colContact = new TableColumn<>("Contact");
colContact.setCellFactory(cell -> buildContactCell());
colContact.setCellValueFactory(cellData -> cellData.getValue().contactInfoProperty());
// **********************************************************************************************
// Need to set the CellValueFactory for colContact here
// **********************************************************************************************
tableView.getColumns().addAll(colName, colContact);
tableView.setItems(getSampleData());
return tableView;
}
private TableCell<Person, ContactInfo> buildContactCell() {
return new TableCell<Person, ContactInfo>() {
final VBox root = new VBox();
final Label lblEmailAddress = new Label();
final Label lblPhoneNumber = new Label();
{
root.getChildren().addAll(lblEmailAddress, lblPhoneNumber);
}
@Override
protected void updateItem(ContactInfo contactInfo, boolean empty) {
super.updateItem(contactInfo, empty);
if (contactInfo != null && !empty) {
lblEmailAddress.setText(contactInfo.getEmailAddress());
lblPhoneNumber.setText(contactInfo.getPhoneNumber());
setGraphic(root);
} else {
setGraphic(null);
}
}
};
}
private ObservableList<Person> getSampleData() {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.addAll(
new Person("Jack", "jack@outlook.com", "123-456-7890"),
new Person("Jenny", "goodtime@yahoo.com", "555-867-5309"),
new Person("Jesse", "mygirl@hotmail.com", "846-989-9988"));
return persons;
}
}
class Person {
private final StringProperty name = new SimpleStringProperty();
private final ObjectProperty<ContactInfo> contactInfoProperty = new SimpleObjectProperty<>();
public Person(String name, String emailAddress, String phoneNumber) {
this.name.set(name);
contactInfoProperty.set(new ContactInfo(emailAddress, phoneNumber));
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public String getEmailAddress() {
return contactInfoProperty.get().emailAddressProperty().get();
}
public StringProperty emailAddressProperty() {
return contactInfoProperty.get().emailAddressProperty();
}
public String getPhoneNumber() {
return contactInfoProperty.get().getPhoneNumber();
}
public StringProperty phoneNumberProperty() {
return contactInfoProperty.get().phoneNumberProperty();
}
public ObjectProperty<ContactInfo> contactInfoProperty() {
return contactInfoProperty;
}
}
class ContactInfo {
private final StringProperty emailAddress = new SimpleStringProperty();
private final StringProperty phoneNumber = new SimpleStringProperty();
public ContactInfo(String emailAddress, String phoneNumber) {
this.emailAddress.set(emailAddress);
this.phoneNumber.set(phoneNumber);
}
public String getEmailAddress() {
return emailAddress.get();
}
public StringProperty emailAddressProperty() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress.set(emailAddress);
}
public String getPhoneNumber() {
return phoneNumber.get();
}
public StringProperty phoneNumberProperty() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber.set(phoneNumber);
}
}
我有一个简单的 Person
对象列表,我正在使用 TableView
来显示:
class Person {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty emailAddress = new SimpleStringProperty();
private final StringProperty phoneNumber = new SimpleStringProperty();
public Person(String name, String emailAddress, String phoneNumber) {
this.name.set(name);
this.emailAddress.set(emailAddress);
this.phoneNumber.set(phoneNumber);
}
}
我在这个例子中的目标是在同一个 TableColumn
中同时显示 emailAddress
和 phoneNumber
。这不仅仅是简单地连接值,因为我正在为此专栏实现自定义 TableCell
(实际应用程序更复杂):
private TableCell<Person, Person> buildContactCell() {
return new TableCell<Person, Person>() {
final VBox root = new VBox();
final Label lblEmailAddress = new Label();
final Label lblPhoneNumber = new Label();
{
root.getChildren().addAll(lblEmailAddress, lblPhoneNumber);
}
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (person != null && !empty) {
lblEmailAddress.setText(person.getEmailAddress());
lblPhoneNumber.setText(person.getPhoneNumber());
setGraphic(root);
} else {
setGraphic(null);
}
}
};
}
我假设这工作正常,但我不确定如何为这个 TableColumn
配置 CellValueFactory
以接受整个 Person
对象。
是否有另一种方法可以设置 TableCell
以访问 Person
中的多个 属性?我在实现多个属性时看到的其他问题只涉及连接,这不是我要找的。
完整代码:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TableCellSample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
root.getChildren().add(getTableView());
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
private TableView<Person> getTableView() {
TableView<Person> tableView = new TableView<>();
TableColumn<Person, String> colName = new TableColumn<>("Name");
colName.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
TableColumn<Person, Person> colContact = new TableColumn<>("Contact");
colContact.setCellFactory(cell -> buildContactCell());
// **********************************************************************************************
// Need to set the CellValueFactory for colContact here
// **********************************************************************************************
tableView.getColumns().addAll(colName, colContact);
tableView.setItems(getSampleData());
return tableView;
}
private TableCell<Person, Person> buildContactCell() {
return new TableCell<Person, Person>() {
final VBox root = new VBox();
final Label lblEmailAddress = new Label();
final Label lblPhoneNumber = new Label();
{
root.getChildren().addAll(lblEmailAddress, lblPhoneNumber);
}
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (person != null && !empty) {
lblEmailAddress.setText(person.getEmailAddress());
lblPhoneNumber.setText(person.getPhoneNumber());
setGraphic(root);
} else {
setGraphic(null);
}
}
};
}
private ObservableList<Person> getSampleData() {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.addAll(
new Person("Jack", "jack@outlook.com", "123-456-7890"),
new Person("Jenny", "goodtime@yahoo.com", "555-867-5309"),
new Person("Jesse", "mygirl@hotmail.com", "846-989-9988"));
return persons;
}
}
class Person {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty emailAddress = new SimpleStringProperty();
private final StringProperty phoneNumber = new SimpleStringProperty();
public Person(String name, String emailAddress, String phoneNumber) {
this.name.set(name);
this.emailAddress.set(emailAddress);
this.phoneNumber.set(phoneNumber);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public String getEmailAddress() {
return emailAddress.get();
}
public StringProperty emailAddressProperty() {
return emailAddress;
}
public String getPhoneNumber() {
return phoneNumber.get();
}
public StringProperty phoneNumberProperty() {
return phoneNumber;
}
}
您的单元格值工厂需要 return 一个包含行元素的 ObjectProperty<Person>
。您可以在单元格值工厂中使用 cellData.getValue()
获取行数据,其中 cellData
是传递给 call()
方法的参数。所以:
colContact.setCellValueFactory(cellData ->
new SimpleObjectProperty<>(cellData.getValue()));
模型应该真正满足视图的需要,让 TableCell 在幕后窥视整个 TableModel 是一种代码味道。组织模型可能更好,这样数据就可以直接用于 TableCell。尝试组合,像这样:
public class TableCellSample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
root.getChildren().add(getTableView());
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
private TableView<Person> getTableView() {
TableView<Person> tableView = new TableView<>();
TableColumn<Person, String> colName = new TableColumn<>("Name");
colName.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
TableColumn<Person, ContactInfo> colContact = new TableColumn<>("Contact");
colContact.setCellFactory(cell -> buildContactCell());
colContact.setCellValueFactory(cellData -> cellData.getValue().contactInfoProperty());
// **********************************************************************************************
// Need to set the CellValueFactory for colContact here
// **********************************************************************************************
tableView.getColumns().addAll(colName, colContact);
tableView.setItems(getSampleData());
return tableView;
}
private TableCell<Person, ContactInfo> buildContactCell() {
return new TableCell<Person, ContactInfo>() {
final VBox root = new VBox();
final Label lblEmailAddress = new Label();
final Label lblPhoneNumber = new Label();
{
root.getChildren().addAll(lblEmailAddress, lblPhoneNumber);
}
@Override
protected void updateItem(ContactInfo contactInfo, boolean empty) {
super.updateItem(contactInfo, empty);
if (contactInfo != null && !empty) {
lblEmailAddress.setText(contactInfo.getEmailAddress());
lblPhoneNumber.setText(contactInfo.getPhoneNumber());
setGraphic(root);
} else {
setGraphic(null);
}
}
};
}
private ObservableList<Person> getSampleData() {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.addAll(
new Person("Jack", "jack@outlook.com", "123-456-7890"),
new Person("Jenny", "goodtime@yahoo.com", "555-867-5309"),
new Person("Jesse", "mygirl@hotmail.com", "846-989-9988"));
return persons;
}
}
class Person {
private final StringProperty name = new SimpleStringProperty();
private final ObjectProperty<ContactInfo> contactInfoProperty = new SimpleObjectProperty<>();
public Person(String name, String emailAddress, String phoneNumber) {
this.name.set(name);
contactInfoProperty.set(new ContactInfo(emailAddress, phoneNumber));
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public String getEmailAddress() {
return contactInfoProperty.get().emailAddressProperty().get();
}
public StringProperty emailAddressProperty() {
return contactInfoProperty.get().emailAddressProperty();
}
public String getPhoneNumber() {
return contactInfoProperty.get().getPhoneNumber();
}
public StringProperty phoneNumberProperty() {
return contactInfoProperty.get().phoneNumberProperty();
}
public ObjectProperty<ContactInfo> contactInfoProperty() {
return contactInfoProperty;
}
}
class ContactInfo {
private final StringProperty emailAddress = new SimpleStringProperty();
private final StringProperty phoneNumber = new SimpleStringProperty();
public ContactInfo(String emailAddress, String phoneNumber) {
this.emailAddress.set(emailAddress);
this.phoneNumber.set(phoneNumber);
}
public String getEmailAddress() {
return emailAddress.get();
}
public StringProperty emailAddressProperty() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress.set(emailAddress);
}
public String getPhoneNumber() {
return phoneNumber.get();
}
public StringProperty phoneNumberProperty() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber.set(phoneNumber);
}
}