来自经验丰富的程序员的问题,他还是Java的新手。
我创建了一个类的原型,该类将类似于Excel的数据过滤器添加到TableView
中的列中。我现在将其设为通用,以便它可以与任何TableView
一起使用,并停留在如何“通用化” Predicate
的创建中。
在我的原型(已对所有内容进行硬编码)中,例如,我为createPredicate()
“值”列调用String
方法,如下所示:
createPredicate(TableViewModel::getTvValue);
,然后在createPredicate()
方法中,像这样设置Predicate
:
private void createPredicate(Function<TableViewModel, String> columnGetter) {
//...
final String filter = "some value";
Predicate<TableViewModel> predicate = tvm -> columnGetter.apply(tvm).contains(filter);
//...
}
如何使对方法的调用和方法本身都具有通用性,以便它们可用于任何TableColumn
?
我被困在两个地方。首先,如何获取TableColumn
的吸气剂,以便将其传递给createPredicate()
方法...
//Get a column
TableColumn<S, T> col = (TableColumn<S, T>) table.getColumns().get(0);
//Set a predicate based on the column
//==>STUCK HERE: How do I get the getter for the column?
createPredicate(S::<WHAT_GOES_HERE?>);
...,其次,如何使contains()
通用。我目前遇到“找不到符号方法contains(T)”编译器错误。
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。我正在使用JavaFX8(JDK1.8.0_181)和NetBeans 8.2。
(裸露的骨头!) TestColumnFilter.java 类:
import java.util.function.Function;
import java.util.function.Predicate;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class TestColumnFilter<S, T> {
public TestColumnFilter(TableView<S> table) {
//Get a column
TableColumn<S, T> col = (TableColumn<S, T>) table.getColumns().get(0);
//Set a predicate based on the column
//STUCK HERE: How to get the getter for the column?
createPredicate(S::<WHAT_GOES_HERE?>);
}
private void createPredicate(Function<S, T> columnGetter) {
final T filter = (T) "some value";
//STUCK HERE: How to genericise the contains?
//Currently getting a "cannot find symbol method contains(T)" compiler error
Predicate<S> predicate = tvm -> columnGetter.apply(tvm).contains(filter);
}
public static <S, T> TestColumnFilter<S, T> createColumnFiltersForTableView(TableView<S> table) {
return new TestColumnFilter<>(table);
}
}
和 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);
}
}
答案 0 :(得分:1)
我认为当前的设计最终不会奏效。
我假设您可以在多个列上设置过滤器,并且TableView
应该基于 all 过滤器显示结果。
您可以尝试这种方法:
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
)进行过滤比较容易。