如何计算TableView中与指定值/字符串匹配的项目数

时间:2018-09-15 16:12:33

标签: java javafx tableview javafx-8

所以我有一个TableView,它具有过滤功能和一些Labels用于显示结果。

  

找到x个人,x是VIP /非VIP,等等。

现在我要做的是计算与TableView中指定的值/字符串相匹配的项目数,以更新 x Labels文本并显示为结果。 (当更改TableView中的项目时,结果应显示并自动更新,而不选择任何行或列)。

对于总共Label人来说,我已经和table.getItems().size()做到了,所以还有3个要去。我的想法是在for loop内创建一个字符串/整数变量,并将其与TableView中的项目进行比较,然后将其包装在listener中以使其自动更新Labels ,但我不知道是否可能。

这是我的代码,您需要从here 添加 controlsfx jar。目前,我将所有Labels置于“清除”按钮的方法上,以手动对其进行更新。

MainApp

import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import org.controlsfx.control.CheckComboBox;


public class MainApp extends Application {
    @Override
    public void start(Stage primaryStage) {
        TableView<Person> table = new TableView<>();
        table.getSelectionModel().setCellSelectionEnabled(true);
        table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        table.getColumns().add(column("Name", Person::nameProperty));
        table.getColumns().add(column("Email", Person::emailProperty));
        table.getColumns().add(column("Gender", Person::genderProperty));
        table.getColumns().add(column("Birthday", Person::birthdayProperty));
        table.getColumns().add(column("Age", Person::ageProperty));
        table.getColumns().add(column("Status", Person::statusProperty));

        ComboBox<Person.Gender> genderFilterCombo = new ComboBox<>();
        genderFilterCombo.getItems().addAll(Person.Gender.values());

        CheckComboBox<Person.Gender> genderFilterCheckCombo= new CheckComboBox<>();
        genderFilterCheckCombo.getItems().addAll(Person.Gender.values());

        CheckComboBox<Person.Status> statusFilterCheckCombo= new CheckComboBox<>();
        statusFilterCheckCombo.getItems().addAll(Person.Status.values());

        TextField nameFilterField = new TextField();
        TextField agefromFilterField = new TextField();
        TextField ageuntilFilterField = new TextField();
        DatePicker datefromFilterField = new DatePicker();
        DatePicker dateuntilFilterField = new DatePicker();

        Label totalperson = new Label();
        Label totalvip = new Label();
        Label totaloldperson = new Label();
        Label totalyoungperson = new Label();

        nameFilterField.setPromptText("Name");
        agefromFilterField.setPromptText("Age from");
        ageuntilFilterField.setPromptText("Age until");
        datefromFilterField.setPromptText("Birthday from");
        dateuntilFilterField.setPromptText("Birthday until");

        ObjectProperty<Predicate<Person>> nameFilter = new SimpleObjectProperty<>();
        ObjectProperty<Predicate<Person>> genderFilter = new SimpleObjectProperty<>();
        ObjectProperty<Predicate<Person>> gender2Filter = new SimpleObjectProperty<>();
        ObjectProperty<Predicate<Person>> datefromFilter = new SimpleObjectProperty<>();
        ObjectProperty<Predicate<Person>> dateuntilFilter = new SimpleObjectProperty<>();
        ObjectProperty<Predicate<Person>> agefromFilter = new SimpleObjectProperty<>();
        ObjectProperty<Predicate<Person>> ageuntilFilter = new SimpleObjectProperty<>();
        ObjectProperty<Predicate<Person>> statusFilter = new SimpleObjectProperty<>();

        nameFilter.bind(Bindings.createObjectBinding(() ->
                        person -> person.getName().toLowerCase().contains(nameFilterField.getText().toLowerCase()),
                nameFilterField.textProperty()));

        genderFilter.bind(Bindings.createObjectBinding(() ->
                        person -> genderFilterCombo.getValue() == null || genderFilterCombo.getValue() == person.getGender(),
                genderFilterCombo.valueProperty()));

        gender2Filter.bind(Bindings.createObjectBinding(() ->
                genderFilterCheckCombo.getCheckModel().getCheckedItems().isEmpty() ?  person-> true : person->
                        genderFilterCheckCombo.getCheckModel().getCheckedItems().contains(person.getGender()),
                genderFilterCheckCombo.getCheckModel().getCheckedItems()));

        datefromFilter.bind(Bindings.createObjectBinding(() ->
                        person -> datefromFilterField.getValue() == null || datefromFilterField.getValue().isBefore(person.getBirthday())
                                || datefromFilterField.getValue().isEqual(person.getBirthday()),
                datefromFilterField.valueProperty()));

        dateuntilFilter.bind(Bindings.createObjectBinding(() ->
                        person -> dateuntilFilterField.getValue() == null || dateuntilFilterField.getValue().isAfter(person.getBirthday())
                                || dateuntilFilterField.getValue().isEqual(person.getBirthday()),
                dateuntilFilterField.valueProperty()));

        agefromFilter.bind(Bindings.createObjectBinding(() ->
                        person -> agefromFilterField.getText().isEmpty() || Integer.parseInt(agefromFilterField.getText()) <= person.getAge(),
                agefromFilterField.textProperty()));

        ageuntilFilter.bind(Bindings.createObjectBinding(() ->
                        person -> ageuntilFilterField.getText().isEmpty() || Integer.parseInt(ageuntilFilterField.getText()) >= person.getAge(),
                ageuntilFilterField.textProperty()));

        statusFilter.bind(Bindings.createObjectBinding(() ->
                        statusFilterCheckCombo.getCheckModel().getCheckedItems().isEmpty() ?  person-> true : person->
                                statusFilterCheckCombo.getCheckModel().getCheckedItems().contains(person.getStatus()),
                statusFilterCheckCombo.getCheckModel().getCheckedItems()));

        FilteredList<Person> filteredItems = new FilteredList<>(FXCollections.observableList(createData()));
        SortedList<Person> sortedData = new SortedList<>(filteredItems);
        sortedData.comparatorProperty().bind(table.comparatorProperty());
        table.setItems(sortedData);

        filteredItems.predicateProperty().bind(Bindings.createObjectBinding(
                () -> nameFilter.get().and(genderFilter.get().and(gender2Filter.get().and(datefromFilter.get().and(dateuntilFilter.get().
                        and(agefromFilter.get().and(ageuntilFilter.get().and(statusFilter.get()))))))),
                nameFilter, genderFilter, gender2Filter, datefromFilter, dateuntilFilter, agefromFilter, ageuntilFilter, statusFilter));

        Button clear = new Button("Clear Filters");
        clear.setOnAction(e -> {
            /*for (TablePosition<Person, ?> pos : table.getSelectionModel().getSelectedCells()) {
                TableColumn<Person, ?> column = pos.getTableColumn();
                ObservableValue<?> obs = column.getCellObservableValue(pos.getRow());
                Object value = obs.getValue();
                System.out.println(value);
                // process value...
            }*/
            nameFilterField.clear();
            datefromFilterField.setValue(null);
            dateuntilFilterField.setValue(null);

        //Here////////////////////////////////////////////////////////////
        int tp = table.getItems().size();
        totalperson.setText(tp + " " + "persons are found!");
        totalvip.setText("x VIP found!");
        totalyoungperson.setText("x are under or equal 25!");
        totaloldperson.setText("x are over 25!");
        });


        FlowPane filters = new FlowPane( nameFilterField, genderFilterCombo, datefromFilterField, dateuntilFilterField, genderFilterCheckCombo, agefromFilterField,
                ageuntilFilterField, statusFilterCheckCombo, clear);
        HBox labels = new HBox(40, totalperson, totalvip, totalyoungperson, totaloldperson);
        filters.setPadding(new Insets(5));
        labels.setPadding(new Insets(5));
        BorderPane root = new BorderPane(table, filters, null, labels, null);
        Scene scene = new Scene(root, 800, 600);


        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private List<Person> createData() {
        return Arrays.asList(
                new Person("Jacob Smith", "jacob.smith@example.com", Person.Gender.MALE, LocalDate.parse("2018-08-25"),25, Person.Status.NONVIP),
                new Person("Jacob Smith", "jacob.smith@example.com", Person.Gender.MALE, LocalDate.parse("2018-08-26"),24, Person.Status.VIP),
                new Person("Jacob Smith", "jacob.smith@example.com", Person.Gender.FEMALE, LocalDate.parse("2018-08-26"),23, Person.Status.VIP),
                new Person("Jacob Smith", "jacob.smith@example.com", Person.Gender.MALE, LocalDate.parse("2018-08-25"),25, Person.Status.NONVIP),
                new Person("Isabella Johnson", "isabella.johnson@example.com", Person.Gender.FEMALE, LocalDate.parse("2018-08-21"),28, Person.Status.VIP),
                new Person("Ethan Williams", "ethan.williams@example.com", Person.Gender.MALE, LocalDate.parse("2018-08-21"),30, Person.Status.VIP),
                new Person("Emma Jones", "emma.jones@example.com", Person.Gender.FEMALE, LocalDate.parse("2018-08-29"),18, Person.Status.NONVIP),
                new Person("Michael Brown", "michael.brown@example.com", Person.Gender.MALE, LocalDate.parse("2018-08-05"),15, Person.Status.NONVIP)
        );
    }

    public static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
        TableColumn<S,T> col = new TableColumn<>(title);
        col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        return col ;
    }


    public static class Person {
//        List<Gender> abc = Arrays.asList(Person.Gender.values());
        public enum Gender {MALE, FEMALE}
        public enum Status {VIP, NONVIP}

        private final StringProperty name = new SimpleStringProperty();
        private final StringProperty email = new SimpleStringProperty() ;
        private final ObjectProperty<Gender> gender = new SimpleObjectProperty<>();
        private final ObjectProperty<LocalDate> birthday = new SimpleObjectProperty<>();
        private final IntegerProperty age = new SimpleIntegerProperty();
        private final ObjectProperty<Status> status = new SimpleObjectProperty<>();

        public Person(String name, String email, Gender gender, LocalDate birthday, Integer age, Status status) {
            setName(name);
            setEmail(email);
            setGender(gender);
            setBirthday(birthday);
            setAge(age);
            setStatus(status);
        }

        public ObjectProperty<Status> statusProperty() { return status; }

        public Status getStatus() { return this.statusProperty().get(); }

        public void setStatus(Status status) { this.statusProperty().set(status); }

        public IntegerProperty ageProperty() { return age; }

        public final int getAge() { return this.ageProperty().get(); }

        public final void setAge(final  Integer age) {this.ageProperty().set(age); }

        public final ObjectProperty<LocalDate> birthdayProperty(){
            return this.birthday;
        }

        public final LocalDate getBirthday() {
            return this.birthdayProperty().get();
        }

        public final void setBirthday(final LocalDate birthday) {
            this.birthdayProperty().set(birthday);
        }

        public final StringProperty emailProperty() {
            return this.email;
        }

        public final String getEmail() {
            return this.emailProperty().get();
        }

        public final void setEmail(final String email) {
            this.emailProperty().set(email);
        }

        public final ObjectProperty<Gender> genderProperty() {
            return this.gender;
        }

        public final Gender getGender() {
            return this.genderProperty().get();
        }

        public final void setGender(final Gender gender) {
            this.genderProperty().set(gender);
        }

        public final StringProperty nameProperty() {
            return this.name;
        }

        public final String getName() { return this.nameProperty().get(); }

        public final void setName(final String name) {
            this.nameProperty().set(name);
        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

2 个答案:

答案 0 :(得分:0)

使用两种类型的构造,可以使用纯JavaFX绑定解决您的问题:

<some-label>.textProperty().bind(Bindings.size(<observable-list>).asString(<some template>));

我试图实现一个最小示例(MCVE),以显示表中所有项目和已过滤项目的数量。我没有使用您的设置,因为我认为它对于MCVE来说太复杂了。我希望该代码可以自我解释,请随时询问是否有混淆或在将其移植到代码时遇到问题。

此应用程序具有一个最小的UI,该UI显示一个表,该表默认具有两个条目和两个标签,一个标签在顶部(显示所有项目的数量),一个标签在底部(显示通过过滤器的项目数量)。由于未显示未通过过滤器的项目,因此无法对其进行编辑以再次通过过滤器,因此,一旦选中复选框或更改名称(取决于活动过滤器),就必须重新启动应用程序。

该示例是一个完整的JavaFX应用程序,您应该能够直接从命令行或使用任何IDE(例如Eclipse:Run As-> Java Application)运行它:

public class FxApp extends Application {

    private ObservableList<PersonController> all = 
        FXCollections.observableArrayList(PersonController::extract);

    private FilteredList<PersonController> filtered = new FilteredList<>(all);

    private TableView<PersonController> table = new TableView<>();

    private TableColumn<PersonController, String> nameColumn = new TableColumn<>("Name");

    private TableColumn<PersonController, Boolean> checkColumn = new TableColumn<>("Check");

    private Label allLabel = new Label(), filteredLabel = new Label();

    @Override
    public void start(Stage stage) throws Exception {
        // Setup items
        all.add(new PersonController("John Doe"));
        all.add(new PersonController("Jane Doe"));
        // Setup UI
        table.setEditable(true);
        table.getColumns().addAll(Arrays.asList(nameColumn, checkColumn));
        nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        nameColumn.setCellValueFactory(features -> features.getValue().nameProperty);
        checkColumn.setCellFactory(CheckBoxTableCell.forTableColumn(checkColumn));
        checkColumn.setCellValueFactory(features -> features.getValue().checkProperty);
        allLabel.textProperty().bind(Bindings.size(all).asString("All items: %s"));
        filteredLabel.textProperty().bind(Bindings.size(filtered).asString("Filtered Items: %s"));
        // You may need to add dependencies of your filter here
        filtered.predicateProperty().bind(Bindings.createObjectBinding(this::buildFilter));
        table.setItems(filtered);
        BorderPane pane = new BorderPane();
        pane.setCenter(table);
        pane.setTop(allLabel);
        pane.setBottom(filteredLabel);
        Scene scene = new Scene(pane);
        stage.setScene(scene);
        stage.show();
    }

    private Predicate<PersonController> buildFilter() {
        return person -> person.checkProperty.not().get();
        // OR
        // return person -> person.nameProperty.get().endsWith("Doe");
        // OR
        // some complex filter using other inputs
    }

    private static class PersonController {

        private StringProperty nameProperty = new SimpleStringProperty();

        private BooleanProperty checkProperty = new SimpleBooleanProperty();

        public PersonController(String name) {
            nameProperty.set(name);
        }

        public Observable[] extract() {
            return new Observable[] { nameProperty, checkProperty };
        }

    }

    public static void main(String[] args) {
        launch(args);
    }

}

答案 1 :(得分:-1)

所以最后是答案。感谢 @James_D here

上发表的帖子
ObservableList<Person> items = table.getItems();

        // initialize counts (only needed once, and only if items is non-empty):
        int vip = 0 ;
        int total = table.getItems().size();
        for (Person item : items) {
            if (Person.Status.VIP.equals(item.getStatus())) vip++ ;
            if (Person.Status.NONVIP.equals(item.getStatus())) nonvip++ ;
        }

        IntegerProperty vipCount = new SimpleIntegerProperty(vip);
        IntegerProperty totalCount = new SimpleIntegerProperty(total);

        totalvip.textProperty().bind(vipCount.asString("VIP: %s"));
        totalperson.textProperty().bind(totalCount.asString("Total persons: %s"));

        items.addListener((
                ListChangeListener.Change<? extends Person> c) -> {
            while (c.next()) {

                if (c.wasAdded()) {
                    for (Person item : c.getAddedSubList()) {
                        totalCount.set(totalCount.get() + 1);
                        if (Person.Status.VIP.equals(item.getStatus())) vipCount.set(vipCount.get() + 1) ;
                    }
                }

                if (c.wasRemoved()) {
                    for (Person item : c.getRemoved()) {
                        totalCount.set(totalCount.get() - 1);
                        item.statusProperty().removeListener(listener);
                        if (Person.Status.VIP.equals(item.getStatus())) vipCount.set(vipCount.get() - 1) ;
                        if(vipCount.get() < 0 ) vipCount.set(0); //prevent negative
                    }
                }

            }
        });