自JavaFX setter/getters以来的最佳实践是最终的?

Tom*_*mmo 1 java getter setter swing javafx

在将Windows应用程序从Swing转换为JavaFX的过程中.例如,我们有很多自定义组件,它们先前覆盖了JTextField的mutator方法.在JavaFX中,这些方法被声明为final.我是否应该创建调用最终方法并在之前和之后修改值的包装器方法?我只是想确保从一开始就以正确的方式做到这一点.

编辑:我还将包括这样的事实:这些代码中的一些来自Java的旧版本.因此,某些事情可能不再是必要的.这是我们在自定义JFormattedTextField中使用的setText方法的示例:

__CODE__

jew*_*sea 6

使用监听器通知变异状态的变化

JavaFX公共API中暴露的几乎所有内容都是属性,因此挂钩到mutate操作的一种方法是添加ChangeListeners(或InvalidationListeners).

有关更多信息,请参阅JavaFX属性文档(从那里复制以下代码段):

import javafx.beans.value.ObservableValue;
import javafx.beans.value.ChangeListener;

public class Main {     
    public static void main(String[] args) {    
        Bill electricBill = new Bill();

        electricBill.amountDueProperty().addListener(new ChangeListener() {
            @Override public void changed(
                 ObservableValue o, 
                 Object oldVal, 
                 Object newVal
            ) {
               System.out.println("Electric bill has changed!");
            }
        });

      electricBill.setAmountDue(100.00);         
    }
}
Run Code Online (Sandbox Code Playgroud)

对于Java 8+,您可以编写:

Label billAmountDue = new Label();
billAmountDue.textProperty().addListener((observable, oldVal, newVal) -> 
    System.out.println("Electric bill has changed!")
);
Run Code Online (Sandbox Code Playgroud)

如果您是子类,则可以在子类的构造函数中设置侦听器.当您覆盖setter函数时,这些侦听器可以执行与您在Swing类中执行的操作类似的工作:

public class AmountLabel extends Label {
    public AmountLabel(String text) {
        super(text);

        textProperty().addListener(observable -> 
            System.out.println("Amount invalidated.")
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

其他问题的答案

那么在更改侦听器中,我会在设置任何掩码后设置适当的值?

嗯,你可以,我以前做过.我不确定这是最好的做法(尽管我不知道另一种方法来处理它).我记得JavaFX属性设计师在一些论坛上评论说他们并没有真正设计更改监听器内更新的属性机制,所以我想它不能保证.

我遇到了一些问题,在更改侦听器中更改WebView的位置属性会导致线程问题,但我认为由于WebView的复杂性,这是一个非常不寻常的案例 - 我提交了一个关于该特定案例的已接受的错误报告.

对于其他控件和属性,您可以使用"监听器中的更新"方法(尽管请参阅下一个后续问题的答案中的警告).

不会在侦听器中设置值会创建无限循环,因为它会在更新值时继续进入ChangeListener.

不,我不认为它创造了无限循环.我认为JavaFX监听器实现中有一些东西会阻止它无限循环.我没有检查源代码以查看它是什么,如果我的重新收集不正确,你需要实现特定的逻辑来防止递归,这将是完全不合需要的,因为它会使不必要的事情复杂化.

由于怀疑短路逻辑可以防止无限递归,如果您在更改侦听器中设置属性的值,我真的不知道更改的值是否会传播到绑定到该属性的所有侦听器或项目(您需要检查实现或编写一些测试来检查行为).

所以这些是我说的原因,虽然它可能在大多数情况下都有效,但在更改监听器中设置值可能不是最佳实践.

如何改变吸气剂?

这个用例似乎比监听设定值更少发生.

我建议创建一个新属性并使用字符串转换器设置双向绑定.字符串转换器的使用是可选的,但它显示了如何监听转换后的值.

特定于格式化的文本字段

您的问题非常通用,但您在帖子中讨论的问题非常特定于格式化文本字段.通用案例是我之前尝试回答的问题.对于格式化文本字段的特定情况,可以应用特定的解决方案.

Richard 建议使用不同的API,replaceText只适用于TextInput:

field = new TextField() {
    @Override public void replaceText(int start, int end, String text) {
        // If the replaced text would end up being invalid, then simply
        // ignore this call!
        if (!text.matches("[a-z]")) {
            super.replaceText(start, end, text);
        }
    }

    @Override public void replaceSelection(String text) {
        if (!text.matches("[a-z]")) {
            super.replaceSelection(text);
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

理查德的帖子现在已经很老了.对于Java 8u40,将包括以下功能:

另一个相关的open-jfx实现项是:

目前还不是9,但是一旦实现,可能有助于为您提出的问题和开发人员在故障单上注明"我们认为提供8u40的示例代码就足够了"提供更具体的用例.

第三方JideFX库包含FormattedTextField类.

关于为什么JavaFX API中的内容是最终的一些背景信息

引用 JavaFX开发人员Richard Bair的话:

一个人的安全.你可以为非最后的课做恶事!这只是一般规则(这就是为什么我们通常希望尽一切可能做到最终).在这种特殊情况下,它可能并不重要.

一条建议

您可能想要做的事情而不是为文本输入格式化程序覆盖getter,就是为格式掩码提供不同的API,而不是格式化的值文本与格式化的值文本.我认为这可能是为了将格式化的JavaFX TextFields添加到Java 8u40所做的.

看看EasyBind

第三方EasyBind库可能有一些很好的方法来处理您想要实现的模式.