列格式化
可重复使用的方法,我在下面的方法我的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());
}
}
};
});
现在这个工程确定,怎么过,我想使这个可重复使用的,我有例如模型是图书,并有不同的获得者,那么这变得不可用。
我能做些什么来使一种方法,我可以申请任何模型对象。我只是为我的GUI使用fxml文件,并且我将hibernate与使用非属性值的模型一起使用(虽然我可以切换,因为我只是测试);但是,
我以这种方式构建我的数据; 我使用hql查询,我后来添加到可观察列表中,然后我将该可观察列表放在tableview;
tableview.setItems(someObservableList);
,并在我的初始化方法,我有
columnX.setCellValueFactory(new PropertyValueFactory("name"));
@FXML
TableColumn columnX;
在这一点上,我有我的所有列填充数据。现在这个棘手的部分,我的模型类的所有原始数据都显示正常,但是对象显示为字符串方法。而这就是为什么我使用的方法,我先挂
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列)。
干杯
在你举的情况下,你应该使用单元格值工厂:
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
。
这里的问题当然是,并非每一列都将在Person
类型的TableView
中,并且并非每一列都将具有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
是Person
和T
是String
),所以你可以这样做:
TableColumn<Person, String> columnExample = column("Name", Person::personNameProperty);
我经常发现,在此设置我不需要除了将它传递给表中的列,因此代码往往最终看起来像
table.getColumns().add(column("Name", Person::personNameProperty));
,如果你可以使用类似的技术真的确实需要一种生成细胞工厂的方法。在您的实例不同的事情是:
- 类型的行中的项目,并在细胞
- ,从该项目的小区(即从项目传递给获得一个
String
功能该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 ;
}
,然后你只是做
TableView<Person> table = new TableView<>();
table.getColumns().add(column("Name", Person::nameProperty, s -> s));
table.getColumns().add(column("Address", Person::addressProperty, Address:shortTextForm));
感谢James_D的一个非常好的回答,但我无法在我的设置中进行此项工作,我更新了我的原始问题,因此如果您可以请帮助:) – ImRaphael
我可能会丢失这里的要点,但是如果你有适当的人类封装,你可能还需要使用PropertyValueFactory。如果person_name是Person类中的属性,那么
columExample.setCellValueFactory(new PropertyValueFactory<Person, String>("person_name"));
应该这样做。
我强烈建议使用lambda表达式代替(遗留) 'PropertyValueFactory'类。 'setCellValueFactory(cellData - > cellData.getValue()。person_nameProperty())'的代码量相当,但运行速度更快(没有反射),(最重要的)是编译时可检查。编译器会查找这个方法,所以如果你在方法名中有一个拼写错误,编译器会捕获它。使用'PropertyValueFactory'你会得到一个你需要跟踪的运行时错误,这可能会更困难。 –
感谢您的提示! – benji2505
为什么你在这种情况下使用细胞工厂,而不是细胞价值工厂? –
显示什么错误? –
好的,你的答案帮了我很大的忙,我得到的错误是一些问题,在我把桌子扔掉之后解决了。感谢你! – ImRaphael