Reputation: 4647
I've written a little example:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class MultipleFilterTextfields extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
VBox vbox = new VBox();
TextField firstNameFilterTextField = new TextField();
TextField lastNameFilterTextField = new TextField();
TableView<Person> tableView = new TableView<>();
ObservableList<Person> list = FXCollections.observableArrayList(new Person("Peter", "Schmidt"),
new Person("Hans-Peter", "Schmidt"), new Person("Hans", "Mustermann"));
FilteredList<Person> filterList = new FilteredList<>(list);
tableView.setItems(filterList);
TableColumn<Person, String> firstNameCol = new TableColumn<>("FirstName");
TableColumn<Person, String> lastNameCol = new TableColumn<>("LastName");
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));
lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
firstNameFilterTextField.textProperty().addListener((obsVal, oldValue, newValue) -> {
filterList.setPredicate(person -> person.getFirstName().contains(newValue));
});
lastNameFilterTextField.textProperty().addListener((obsVal, oldValue, newValue) -> {
filterList.setPredicate(person -> person.getLastName().contains(newValue));
});
tableView.getColumns().addAll(firstNameCol, lastNameCol);
vbox.getChildren().addAll(firstNameFilterTextField, lastNameFilterTextField, tableView);
Scene scene = new Scene(vbox, 250, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
super();
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
public static void main(String[] args) {
launch(args);
}
}
It looks like this:
Above the tableView
there are two TextField
s, one to filter the firstName
and the other to filter the lastName
. Each of them filters the whole tableView
:
If I type in the first field: "Hans", the table filters the two persons "Hans-Peter Schmidt" and "Hans Mustermann". If I type in "Schmidt" in the second one, it filters "Peter Schmidt" and "Hans-Peter Schmidt".
The problem is, that I can't filter (with the code above) for firstName
AND lastName
at the same time.
Do you have any ideas?
Thanks for your help!
Upvotes: 3
Views: 2461
Reputation: 209235
How about
filteredList.predicateProperty().bind(Bindings.createObjectBinding(() ->
person -> person.getFirstName().contains(firstNameFilterTextField.getText())
&& person.getLastName().contains(lastNameFilterTextField.getText()),
firstNameFilterTextField.textProperty(),
lastNameFilterTextField.textProperty()
));
instead of the two listeners on the text fields.
Bindings.createObjectBinding(...)
takes a function generating the computed value, along with a list of any properties that the binding has to observe. In this case, we want to recompute if either of the text fields change, so the list of properties is the text properties of the two text fields.
The function has to return a predicate, so it is of the form () -> predicate
.
The predicate itself is a function mapping a Person
to a boolean
, so the predicate looks like person -> condition
, and the overall form of the first parameter is
() -> person -> condition
Note you could still do this with two listeners:
firstNameFilterTextField.textProperty().addListener((obsVal, oldValue, newValue) -> {
filterList.setPredicate(person -> person.getFirstName().contains(firstNameFilterTextField.getText())
&& person.getLastName().contains(lastNameFilterTextField.getText()));
});
lastNameFilterTextField.textProperty().addListener((obsVal, oldValue, newValue) -> {
filterList.setPredicate(person -> person.getFirstName().contains(firstNameFilterTextField.getText())
&& person.getLastName().contains(lastNameFilterTextField.getText()));
});
but the single binding seems more elegant (to me).
Upvotes: 5