在将Windows应用程序从Swing转换为JavaFX的过程中。例如,我们有很多自定义组件,它们先前覆盖了JTextField的mutator方法。在JavaFX中,这些方法被声明为final。我是否应该创建调用最终方法并在之前和之后修改值的包装器方法?我只是想确保从一开始就以正确的方式去做。
编辑:我还将包括这样的事实:这些代码中的一些来自Java的旧版本。因此,某些事情可能不再是必要的。这是我们在自定义JFormattedTextField中使用的setText方法的一个示例:
public void setText(String text) {
String newString = "";
if(mask == null) {
newString = text;
unformattedCurrent = newString;
}
else {
newString = applyMask(text);
}
super.setText(newString);
if(text.trim().length() == 0) {
positionCaret(0);
selectRange(0, 0);
}
else {
int length = getFormattedText().length();
if(isFocused() && length == getCaretPosition()) {
super.selectAll();
}
}
}
答案 0 :(得分:6)
使用听众通知变异状态的变化
JavaFX公共API中暴露的几乎所有内容都是属性,因此挂钩到mutate操作的一种方法是添加ChangeListeners
(或InvalidationListeners
)。
有关详细信息,请参阅JavaFX property documentation(从那里复制以下代码段):
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);
}
}
对于Java 8+,您可以写:
Label billAmountDue = new Label();
billAmountDue.textProperty().addListener((observable, oldVal, newVal) ->
System.out.println("Electric bill has changed!")
);
如果您是子类,则可以在子类的构造函数中设置侦听器。当你重写setter函数时,这些监听器可以执行类似于你在Swing类中所做的工作:
public class AmountLabel extends Label {
public AmountLabel(String text) {
super(text);
textProperty().addListener(observable ->
System.out.println("Amount invalidated.")
);
}
}
其他问题的解答
因此,在更改侦听器中,我会在设置任何掩码后设置适当的值吗?
嗯,你可以,我以前做过。我不确定这样做是否是最好的做法(虽然我不知道另外一种方法来处理它)。我记得JavaFX属性设计师在一些论坛上评论说他们并没有真正设计更改监听器内更新的属性机制,所以我想这不能保证。
我遇到过在更改侦听器中更改WebView的位置属性导致线程问题的问题,但我认为由于WebView的复杂性,这是一个非常不寻常的情况 - 我提交了一份关于该特定的错误报告案件。
对于其他控件和属性,您可以在监听器中使用"更新"方法(尽管在下一个后续问题的答案中看到了警告)。
不会在侦听器中设置值会创建一个无限循环,因为它会在更新值时继续进入ChangeListener。
不,我不认为它会创造一个无限循环。我认为JavaFX监听器实现中有一些东西会阻止它无限循环。我还没有检查源代码,看看它是什么,如果我的回忆不正确,你需要实现特定的逻辑来防止递归,这将是完全不受欢迎的,因为它会使不必要的事情复杂化。
由于怀疑短路逻辑可以防止无限递归,如果你在更改侦听器中设置属性的值,我真的不知道更改的值是否会传播到所有侦听器或绑定的项目到该属性(您需要检查实现或编写一些测试来检查行为)。
所以这些是我说的原因,虽然它可能在大多数情况下有用,但在更改监听器中设置值可能不是最佳做法。
改变吸气剂怎么样?
这个用例似乎比监听设定值更少发生。
我建议创建一个新属性并设置bidirectional binding with a string converter。字符串转换器的使用是可选的,但它显示了如何监听转换后的值。
特定于格式化文本字段
您的问题很通用,但您在帖子中讨论的问题非常特定于格式化文本字段。通用案例是我之前尝试回答的问题。对于格式化文本字段的特定情况,可以应用特定的解决方案。
Richard recommends using a different API altogether,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);
}
}
};
理查德的帖子现在已经很老了。对于Java 8u40,将包含以下功能:
另一个相关的open-jfx实现项是:
目前还不是9,但是一旦实施,可能有助于为您提出的问题提供一些进一步的具体用例,并且开发人员会在票证上注明"我们认为提供示例代码就足够了8u40&#34 ;.
第三方JideFX library includes a FormattedTextField class。
有关JavaFX API中的内容为何最终的背景信息
Quote from Richard Bair,领导JavaFX开发人员:
一个人的安全。你可以为非最后的课做恶事!这只是一般规则(这就是为什么我们通常希望尽一切可能做到最终)。在这种特殊情况下,它可能并不重要。
建议
您可能想要做的事情而不是为文本输入格式化程序覆盖getter,就是为格式掩码提供不同的API,而不是格式化值文本与格式化值文本。我认为这可能是将格式化的JavaFX TextFields添加到Java 8u40中所做的。
查看EasyBind
第三方EasyBind库可能有一些很好的方法来处理你想要实现的模式。