[英]TornadoFX/JavaFX - filter an observable list based on another observable property
I'm having some difficulty figuring out a relatively simple filtering configuration with TorandoFX.我在使用 TorandoFX 找出相对简单的过滤配置时遇到了一些困难。 I would like to create a
FilteredList
(backed by an ObservableList
) based on a SimpleStringProperty
.我想基于
SimpleStringProperty
创建一个FilteredList
(由ObservableList
支持)。 The filter operation should be "bound" to the string property, so that any updates to the property automatically re-execute the filter operation.过滤操作应该“绑定”到字符串属性,这样对属性的任何更新都会自动重新执行过滤操作。
For example, say I want to filter the list based on the length of the string property so that all elements in the FilteredList
have length >= the string property .例如,假设我想根据字符串属性的长度过滤列表,以便
FilteredList
中的所有元素的长度 >= 字符串属性。 The following does not work.以下不起作用。
val prop = SimpleStringProperty()
val baseList = listOf("a", "aa", "aaa", "b", "bb", "bbb")
val filteredList = FilteredList(baseList){ t -> prop.length().lessThanOrEqualTo(t.length).get()}
I hooked this interface into a GUI, but as I type into the textfield (bound to the SimpleStringProperty
the combobox (bound to the filteredList
) does not change.我将此界面连接到 GUI 中,但是当我输入文本字段(绑定到
SimpleStringProperty
,组合框(绑定到filteredList
)不会改变。
How do I make this code work?我如何使此代码工作?
I don't know Kotlin/TornadoFX, but here's a JavaFX solution you (or others) may be able to translate.我不知道 Kotlin/TornadoFX,但这里有一个 JavaFX 解决方案,您(或其他人)可以翻译。
The basic idea is to create the FilteredList
and bind its predicateProperty
to a Predicate
that depends on the appropriate StringProperty
.基本思想是创建
FilteredList
并将其predicateProperty
绑定到依赖于适当StringProperty
的Predicate
。 There are various library methods for creating such a binding.有多种库方法可用于创建此类绑定。 Eg you can do:
例如你可以这样做:
filteredList = new FilteredList<>(baseList);
filteredList.predicateProperty().bind(
new ObjectBinding<>() {
{
super.bind(prop);
}
@Override
public Predicate<String> computeValue() {
return t -> t.length() > prop.get().length() ;
}
}
);
You can also use the Bindings.createBinding()
method, which takes a Callable<Predicate<String>>
and a list of observables to observe (and if any are invalidated, recompute):您还可以使用
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
));
Without the commentary, that reduces to the concise (but mind-boggling)如果没有评论,那就简化为简洁(但令人难以置信)
filteredList.predicateProperty().bind(Bindings.createObjectBinding(
() -> t -> t.length() > prop.get().length(),
prop
));
Here's a complete example:这是一个完整的例子:
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); }
}
I figured it out.我想到了。 Thanks to James_D for pointing me in the right direction with Predicates .
感谢James_D用Predicates为我指明了正确的方向。 And thanks to others who have provided examples in JavaFX (which guided me to the TornadoFX/Kotlin answer).
并感谢在 JavaFX 中提供示例的其他人(它引导我找到了 TornadoFX/Kotlin 的答案)。
Here's the answer in 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}
}
The magic here is the filterWhen
( see docs ) method.这里的
filterWhen
在于filterWhen
(参见文档)方法。 For reasons I don't understand, it's only available on a SortedFilteredList
, not a plain FilteredList
.出于我不明白的原因,它仅适用于
SortedFilteredList
,而不是普通的FilteredList
。 filterWhen
lets you explicitly declare what properties are to be observed for change and the filter re-run each time. filterWhen
允许您明确声明要观察哪些属性以进行更改,并且过滤器每次都重新运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.