JavaFX - 多个文本字段应过滤一个tableview

时间:2015-10-08 12:38:54

标签: java javafx

我写了一个小例子:

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);
    }
}

看起来像这样:

enter image description here

tableView之上有两个TextField,一个用于过滤firstName,另一个用于过滤lastName。他们每个人都会过滤整个tableView

如果我输入第一个字段:“Hans”,表格会过滤两个人“Hans-Peter Schmidt”和“Hans Mustermann”。如果我在第二个中键入“Schmidt”,它会过滤“Peter Schmidt”和“Hans-Peter Schmidt”。

问题是,我无法同时过滤(使用上面的代码)firstNamelastName

你有什么想法吗?

感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

怎么样

filteredList.predicateProperty().bind(Bindings.createObjectBinding(() ->
    person -> person.getFirstName().contains(firstNameFilterTextField.getText())
           && person.getLastName().contains(lastNameFilterTextField.getText()),

    firstNameFilterTextField.textProperty(),
    lastNameFilterTextField.textProperty()

));

而不是文本字段上的两个侦听器。

Bindings.createObjectBinding(...)接受一个生成计算值的函数,以及绑定必须遵守的任何属性的列表。在这种情况下,如果任一文本字段发生更改,我们希望重新计算,因此属性列表是两个文本字段的文本属性。

该函数必须返回谓词,因此它的格式为() -> predicate。 谓词本身是将Person映射到boolean的函数,因此谓词看起来像person -> condition,第一个参数的整体形式是

() -> person -> condition

请注意,您仍然可以使用两个侦听器执行此操作:

    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()));
    });

但单一绑定似乎更优雅(对我而言)。