有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaFX/JavaFX根据另一个可观察属性过滤可观察列表

我很难用TorandoFX找到一个相对简单的过滤配置。我想基于SimpleStringProperty创建一个FilteredList(由ObservableList支持)。筛选器操作应“绑定”到string属性,以便对该属性的任何更新都会自动重新执行筛选器操作

例如,假设我想根据string属性的长度过滤列表,以便FilteredList中的所有元素都具有长度>;=字符串属性。以下方法不起作用

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) 个答案

  1. # 1 楼答案

    我不知道Kotlin/TornadFX,但这里有一个JavaFX解决方案,您(或其他人)可以翻译

    基本思想是创建FilteredList并将其predicateProperty绑定到一个Predicate上,该StringProperty取决于合适的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); }
    
    }
    
  2. # 2 楼答案

    我想出来了。感谢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}
    }
    

    这里的魔法是filterWhensee docs)方法。出于我不理解的原因,它只在SortedFilteredList上可用,而不是普通的FilteredListfilterWhen允许您明确声明要观察哪些属性以进行更改,并且每次都会重新运行筛选器