我的javafx应用程序中有以下方法:
columExample.setCellFactory((TableColumn<Person, Person> column) -> {
return new TableCell<Peson, Person>() {
@Override
protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
setText(item.getPerson_name());
}
}
};
});
现在这个工作正常,但是,我想让这个可重复使用,我有例如Book的模型,并且有不同的getter,然后这变得无法使用。
我可以做一个方法,我可以申请任何Model对象。
[编辑] 稍微澄清一下,我正在为我的GUI使用fxml文件,我正在使用hibernate与使用非属性值的模型(虽然我可以切换,因为我只是测试);
我以这种方式构建我的数据; 我使用hql查询,我后来添加到observable列表,然后我将该可观察列表放在tableview上;
tableview.setItems(someObservableList);
在我的初始化方法中我有
columnX.setCellValueFactory(new PropertyValueFactory("name"));
@FXML
TableColumn columnX;
此时我的所有列都填充了数据。现在是棘手的部分,我的模型类中的所有原始数据都显示正常,但是对象字符串方法显示了objecst。这就是为什么我使用我首先链接的方法
columExample.setCellFactory((TableColumn<Person, Person> column) -> {
return new TableCell<Peson, Person>() {
@Override
protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
setText(item.getPerson_name());
}
}
};
});
所以我只得到人名,而不是整个字符串方法。
那么有什么简单的方法可以做到这一点
TableColumn<Person, String> columnExample = new TableColumn<>("Name");
columnExample.setCellValueFactory(cellData ->
new SimpleStringProperty(cellData.getValue().getPersonName()));
因为我无法在我当前的设置中使用它,我的程序只是在应用程序启动时显示错误。(我假设因为这会创建新的tablecolum,我希望将其应用于我当前的@FXML列。)
干杯
答案 0 :(得分:2)
在您引用的情况下,您应该使用单元格值工厂:
TableColumn<Person, String> columnExample = new TableColumn<>("Name");
columnExample.setCellValueFactory(cellData ->
new SimpleStringProperty(cellData.getValue().getPersonName()));
然后默认的单元工厂会做你想要的。
如果您使用JavaFX property pattern实施模型,即您有
public class Person {
private final StringProperty personName = new SimpleStringProperty();
public StringProperty personNameProperty() {
return personName ;
}
public final String getPersonName() {
return personNameProperty().get();
}
public final void setPersonName(String name) {
personNameProperty().set(name);
}
}
然后这就变成了
TableColumn<Person, String> columnExample = new TableColumn<>("Name");
columnExample.setCellValueFactory(cellData -> cellData.getValue().personNameProperty());
我经常使用实用程序方法来创建列以减少代码。基本思想是编写一个参数化变化的方法。在前两行中,根据您创建的列而变化的内容是:
"Name"
)的文本和Person
实例)到包含要显示的值的属性的函数。第一个很简单:它只是String
。第二个有点棘手:你可以将它表示为Function<Person, StringProperty>
,它将被定义为lambda表达式p -> p.personNameProperty()
或方法引用Person::personNameProperty
。
这里的问题当然是,并非每个列都属于TableView
类型Person
,而且并非每列都有String
类型。所以我们也需要对它们进行参数化。这可以通过使用两个类型参数定义泛型方法来完成。我们将Person
替换为类型参数,例如S
,将String
替换为第二个类型参数,例如T
。然后我们正在创建TableColumn<S,T>
,我们需要Function<S, Property<T>>
。所以方法如下:
private <S,T> TableColumn<S,T> column(String text, Function<S, Property<T>> prop) {
TableColumn<S,T> col = new TableColumn<>(text);
col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
return col ;
}
你可以用
来调用它TableColumn<Person, String> columnExample = this.<Person, String>column("Name", Person::personNameProperty);
在Java 8中,编译器可以推断出方法的泛型类型(基本上,它看到Person::personNameProperty
是Function<Person, Property<String>>
,因此它推断出S
是{{1 }}和Person
是T
),所以你可以这样做:
String
我经常发现使用此设置我不需要列,除非将其传递到表中,因此代码通常看起来像
TableColumn<Person, String> columnExample = column("Name", Person::personNameProperty);
如果确实需要一种生成单元工厂的方法,则可以使用类似的技术。您的示例中的内容有所不同:
table.getColumns().add(column("Name", Person::personNameProperty));
的函数(即从传递给String
方法的项目中获取){/ li>
醇>
所以第一个是通过创建一个通用方法来解决的,updateItem(...)
返回<S,T>
。第二个是通过使用Callback<TableColumn<S,T>, TableCell<S,T>>
类型的参数来解决的,该参数将单元格项(类型Function<T, String>
)映射到T
:
String
然后您的原始示例变为
public <S,T> Callback<TableColumn<S,T>, TableCell<S,T>>
cellFactory(Function<T, String> textExtractor) {
return col -> new TableCell<S,T>() {
@Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty) ;
if (empty || item == null) {
setText(null);
} else {
setText(textExtractor.apply(item));
}
}
};
}
最后,如果您需要,您可以将所有这些想法结合起来。假设您有一个columnExample.setCellFactory(cellFactory(Person::getPersonName));
类:
Address
和public class Address {
private String street ;
private String city ;
// etc etc
public String shortTextForm() {
return street+" ,"+city;
}
// ...
}
类:
Person
现在创建一个可重用的方法来创建列。这个将设置public class Person {
private final StringProperty name = new SimpleStringProperty();
public StringProperty nameProperty() {
return name ;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty().set(name);
}
private final ObjectProperty<Address> address = new SimpleObjectProperty<>();
public ObjectProperty<Address> addressProperty() {
return address ;
}
public Address getAddress() {
return addressProperty().get();
}
public void setAddress(Address address) {
addressProperty().set(address);
}
// other properties...
}
(因此需要cellValueFactory
)和Function<S,Property<T>>
(因此需要cellFactory
):
Function<T, String>
然后你就做了
private <S,T> TableColumn<S,T> column(String text, Function<S,Property<T>> prop,
Function<T,String> textExtractor) {
TableColumn<S,T> col = new TableColumn<>(text);
col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
col.setCellFactory(c -> new TableCell<S,T>() {
@Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
setText(textExtractor.apply(item));
}
}
});
return col ;
}
答案 1 :(得分:0)
我可能会忽略这一点,但如果您对person类进行了适当的封装,那么您可以使用PropertyValueFactory。如果person_name是Person类中的属性,则
columExample.setCellValueFactory(new PropertyValueFactory<Person, String>("person_name"));
应该做的伎俩。