5

我想在 JavaFX 中实现类似于函数式反应式编程的东西,我认为由于 JavaFX 已经支持侦听器和属性之间的绑定,它应该相当容易,所以我创建了用于绑定转换的小型框架,例如,我现在可以做类似的事情这个(Scala中的例子,但应该可以理解我的意思):

val property1: Property[String]
val property2: Property[Path]

Bindings.Conversions
    .bindUni(property1).to(property2)
    .using(p => p.getFileName.toString)
    .connect()

在这里,我通过一个转换函数绑定property2(which is a java.nio.file.Path) 的值,该函数采用路径的最后一部分并将字符串转换为property1(which is string)。

它的实现非常简单(即使对于双向绑定;我只是从 openjfxBidirectionalBinding类中获取一些代码,将其翻译成 Scala 并对其进行调整以进行转换),我想知道为什么 JavaFX 中还没有这样的东西。

这一切都很好,我什至可以创建这种绑定的复杂链。除非转换函数依赖于某些外部状态,否则一切正常。

例如,假设您有以下绑定链:

Text field value  -1->  intermediate java.nio.file.Path  -2->  another String  -->  Label

当文本字段发生变化时,PathString自动重新计算,并将 String 属性的值写入标签。一切都很棒。但是假设-2->转换应该取决于某些复选框的切换状态:

                                       Checkbox state  ---+
                                                          |
Text field value  -1->  intermediate java.nio.file.Path  -2->  another String  -->  Label

也就是说,当复选框被选中时,转换应该略有不同。

显然,直接实现这种构造是行不通的,因为复选框状态的更改不会切换转换链的重新计算。但是,我发现 JavaFX 没有提供任何强制更改事件的方法。SimpleStringProperty例如,我尝试覆盖并公开其fireValueChangedEvent()方法,但这并没有帮助。目前我正在做类似的事情,textField.setText(""); textField.setText(oldValue);但这丑陋,显然不是正确的方法。

我是否错过了什么,真的可以做我想做的事,或者根本没有这样的事情,我在这里完全搞砸了?

如果答案是否定的,那么我认为这会严重损害整个框架的表现力。我知道我真的可以对许多听众做我想做的事,但这会很丑陋,我想让整个事情尽可能笼统。

4

2 回答 2

1

您可以CheckBox#selectedProperty()像收听 String 属性一样收听。请参见下一个示例:

public class ConditionalBind extends Application {

    Label label = new Label();
    TextField tf = new TextField("hi");
    CheckBox cb = new CheckBox("lowerize");

    @Override
    public void start(Stage primaryStage) {

        label.textProperty().bind(new StringBinding() {

            {
                bind(tf.textProperty(), cb.selectedProperty());
            }

            @Override
            protected String computeValue() {
                return cb.isSelected() ? tf.getText().toLowerCase() : tf.getText();
            }
        });

        VBox root = new VBox(10);
        root.getChildren().addAll(label, cb, tf);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
于 2013-06-11T22:43:13.693 回答
0

作为“丑陋”的解决方法,我最终随机更改了值而不改变含义。例如,对于一个双精度值,我会添加一个小的随机量来强制更改,或者对于一个字符串值,我会切换和不可见的空间。这一切都不好,但会得到触发属性更改的效果。

在多线程环境中情况会变得更糟。如果绑定恰好在属性的初始设置之后稍许,则可能会发生有界属性不会获得更改触发器的情况。如果您现在将属性设置为相同的值,则该值将被视为未更改,并且有界属性将不会获取初始值,而是保持为空值或默认值。十分难看!

于 2017-07-07T21:47:35.833 回答