Generics 如何在JavaFX8中泛化TableView的FilteredList的谓词创建?
一位经验丰富的程序员提出的问题,他对Java还比较陌生 我创建了一个类的原型,该类将类似Excel的数据过滤器添加到TableView中的列中。我现在将它变成泛型的,这样它就可以与任何TableView一起工作,并且我一直在研究如何泛型谓词的创建 在我的原型中,我硬编码了所有内容,例如,我为字符串值列调用createPredicate方法,如下所示:Generics 如何在JavaFX8中泛化TableView的FilteredList的谓词创建?,generics,javafx,tableview,javafx-8,Generics,Javafx,Tableview,Javafx 8,一位经验丰富的程序员提出的问题,他对Java还比较陌生 我创建了一个类的原型,该类将类似Excel的数据过滤器添加到TableView中的列中。我现在将它变成泛型的,这样它就可以与任何TableView一起工作,并且我一直在研究如何泛型谓词的创建 在我的原型中,我硬编码了所有内容,例如,我为字符串值列调用createPredicate方法,如下所示: createPredicate(TableViewModel::getTvValue); private void createPredicat
createPredicate(TableViewModel::getTvValue);
private void createPredicate(Function<TableViewModel, String> columnGetter) {
//...
final String filter = "some value";
Predicate<TableViewModel> predicate = tvm -> columnGetter.apply(tvm).contains(filter);
//...
}
在createPredicate方法中,我将谓词设置为:
createPredicate(TableViewModel::getTvValue);
private void createPredicate(Function<TableViewModel, String> columnGetter) {
//...
final String filter = "some value";
Predicate<TableViewModel> predicate = tvm -> columnGetter.apply(tvm).contains(filter);
//...
}
。。。第二,如何使包含泛型。我当前遇到找不到符号方法containsT编译器错误
private void createPredicate(Function<S, T> columnGetter) {
final T filter = (T) "some value";
//STUCK HERE: How to genericise the contains?
Predicate<S> predicate = tvm -> columnGetter.apply(tvm).contains(filter);
}
提前谢谢。如果有帮助,这里有一个MVCE。我使用的是JavaFX8JDK1.8.0µ和NetBeans8.2
光秃秃的骨头!TestColumnFilter.java类:
Test55.java,一个使用TestColumnFilter.java的虚拟类
import java.util.Arrays;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Test55 extends Application {
private Parent createContent() {
TableView<TableViewModel> table = new TableView<>();
TableColumn<TableViewModel, String> valueCol = new TableColumn<>("Value");
valueCol.setCellValueFactory(cb -> cb.getValue().tvValueProperty());
table.getColumns().addAll(Arrays.asList(valueCol));
TestColumnFilter.createColumnFiltersForTableView(table);
BorderPane content = new BorderPane(table);
return content;
}
private class TableViewModel {
private final StringProperty tvValue;
public TableViewModel(
String tvValue
) {
this.tvValue = new SimpleStringProperty(tvValue);
}
public String getTvValue() {return tvValue.get().trim();}
public void setTvValue(String tvValue) {this.tvValue.set(tvValue);}
public StringProperty tvValueProperty() {return tvValue;}
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle("Test");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我认为目前的设计最终不会成功 我假设您可以在多个列上设置过滤器,TableView应该显示基于所有过滤器的结果 您可以尝试以下方法:
public class TableViewFilter<S> {
private final TableView<S> tableView;
private final FilteredList<S> filteredItems;
private final ObservableList<Function<S, Boolean>> conditions;
public TableViewFilter(TableView<S> tableView, ObservableList<S> items) {
this.tableView = tableView;
this.filteredItems = new FilteredList<>(items);
this.tableView.setItems(filteredItems ).
this.conditions = FXCollections.observableArrayList();
this.filteredItems.predicateProperty().bind(
Bindings.createObjectBinding(this::generatePredicate, this.conditions));
}
public static <S> TableViewFilter<S> forTableView(TableView<S> tableView) {
return new TableViewFilter<>(tableView);
}
public void addCondition(Function<S, Boolean> condition) {
conditions.add(condition);
}
private Predicate<S> generatePredicate() {
return item -> {
return conditions.stream().map(func -> func.apply(item)).allMatch(Boolean.TRUE::equals);
};
}
}
TableView<TableViewModel> table = new TableView<>();
TableColumn<TableViewModel, String> valueCol = new TableColumn<>("Value");
valueCol.setCellValueFactory(cb -> cb.getValue().tvValueProperty());
table.getColumns().addAll(Arrays.asList(valueCol));
ObservableList<TableViewModel> items = FXCollections.observableArrayList();
items.addAll(/*items*/);
//TestColumnFilter.createColumnFiltersForTableView(table);
TableViewFilter filter = TableViewFilter.forTableView(table, items); // Keep a reference if you need to add more conditions later
filter.addCondition(item -> item.getTvValue().contains("filtered string"));
BorderPane content = new BorderPane(table);
return content;
}
请注意,该条件不依赖于特定的TableColumn。使用基础数据(即TableViewModel)进行过滤更容易。您好,Jai,非常感谢您的回复。是的,您的假设是正确的–可以筛选多个列,并且每个列可能有多个筛选值。TableView将显示所有过滤器的结果。我可以看到你的代码是如何工作的,我会试一试。不过,请给我几天时间来使用它,因为我不熟悉您使用的一些语法,还需要做一些研究。一个问题:有没有一种方法可以获得TableColumn的getter?我试着得到它的细胞价值工厂,但不知道从那里去哪里。干杯@GreenZebra您的方法很奇怪,因为这里的每个TableColumn只表示表的模式。为特定列设置单元格工厂时,您告诉该列如何获取表中每一行的值。由于单元工厂用于确定单元的值,因此不可能将其反转以检索整个列中通用的getter函数。我现在明白了为什么我的方法很奇怪,效果不好。所以,我决定从头开始!我会尝试你的方法。我会看看我是怎么做的。谢谢你的提示。干杯,你好,洁。只是让你知道我能让你的代码正常工作。我更改了这个.tableView.setItemsitems。到this.tableView.setItemsfilteredItems;成功地过滤了一列。现在让它为多个列工作,每个列都有多个值。再次干杯@绿斑马很高兴知道它起作用了。这应该适用于多种情况。请注意,我的示例使用AND逻辑连接所有条件,即每一行必须满足所有条件,才能通过Stream::allMatch过滤掉。如果希望在满足任何条件时过滤掉条目,则可以将其更改为Stream::anyMatch。