TornadoFX / JavaFX - отфильтровать наблюдаемый список на основе другого наблюдаемого свойства - PullRequest
0 голосов
/ 04 марта 2020

У меня возникли некоторые затруднения в определении относительно простой конфигурации фильтрации с TorandoFX. Я хотел бы создать FilteredList (при поддержке ObservableList) на основе SimpleStringProperty. Операция фильтра должна быть «привязана» к строковому свойству, чтобы любые обновления свойства автоматически повторно выполняли операцию фильтрации.

Например, скажем, я хочу отфильтровать список на основе длина свойства строки, так что все элементы в FilteredList имеют length> = свойство строки . Следующее не работает.

val prop = SimpleStringProperty()
val baseList = listOf("a", "aa", "aaa", "b", "bb", "bbb")
val filteredList = FilteredList(baseList){ t -> prop.length().lessThanOrEqualTo(t.length).get()}

Я подключил этот интерфейс к GUI, но когда я набираю текстовое поле (привязанное к SimpleStringProperty, поле со списком (привязанное к filteredList) делает не меняется.

Как заставить этот код работать?

Ответы [ 2 ]

0 голосов
/ 04 марта 2020

Я понял это. Спасибо James_D за указание мне в правильном направлении с Предикатами . И спасибо другим, которые предоставили примеры в JavaFX (которые привели меня к ответу TornadoFX / Kotlin).

Вот ответ в Kotlin:

val prop = SimpleStringProperty()
val baseList = listOf("a", "aa", "aaa", "b", "bb", "bbb")
val filteredList = SortedFilteredList(baseList).apply {
        filterWhen(prop) {prop, item -> (prop?.length ?: 0) <= item.length}
}

Волхвы c здесь используется метод filterWhen ( смотри документы ). По причинам, которые я не понимаю, он доступен только для SortedFilteredList, а не для простого FilteredList. filterWhen позволяет вам явно объявить, какие свойства должны соблюдаться при изменении, и фильтр каждый раз перезапускается.

0 голосов
/ 04 марта 2020

Я не знаю Kotlin / TornadoFX, но вот решение JavaFX, которое вы (или другие) можете перевести.

Основная идея c состоит в том, чтобы создать FilteredList и связать его. predicateProperty до Predicate, что зависит от соответствующего StringProperty. Существуют различные библиотечные методы для создания такой привязки. Например, вы можете сделать:

filteredList = new FilteredList<>(baseList);
filteredList.predicateProperty().bind(
    new ObjectBinding<>() {
        {
            super.bind(prop);
        }
        @Override
        public Predicate<String> computeValue() {
            return t -> t.length() > prop.get().length() ;
        }
    }
);

Вы также можете использовать метод Bindings.createBinding(), который принимает Callable<Predicate<String>> и список наблюдаемых для наблюдения (и, если они недействительны, пересчитайте):

filteredList.predicateProperty().bind(Bindings.createObjectBinding(
    // Callable<Predicate<String>> expressed as a lambda: () -> Predicate<String>
    () ->
        // Predicate<String> expressed as a lambda: String -> boolean
        t -> t.length() > prop.get().length(),
    prop
));

Без комментариев это сводится к краткому (но ошеломляющему)

filteredList.predicateProperty().bind(Bindings.createObjectBinding(
    () -> t -> t.length() > prop.get().length(),
    prop
));

Вот полный пример:

import static javafx.beans.binding.Bindings.createObjectBinding;

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.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class FilteredListExample extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        ObservableList<String> baseList = FXCollections.observableArrayList("a", "aa", "aaa", "b", "bb", "bbb");
        FilteredList<String> filteredList = new FilteredList<>(baseList);

        ListView<String> listView = new ListView<>(filteredList);

        TextField input = new TextField();

        filteredList.predicateProperty().bind(createObjectBinding(
                () -> t -> t.length() >= input.getText().length(),
                input.textProperty()));


        BorderPane root = new BorderPane(listView, input, null, null, null) ;
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...