在将Windows应用程序从Swing转换为JavaFX的过程中。例如,我们有很多自定义组件,这些组件以前覆盖了JTextField的mutator方法。在JavaFX中,这些方法被声明为final。我是否应该只创建调用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();
}
}
}
最佳答案
使用侦听器通知突变状态的变化
JavaFX公共API中公开的几乎所有内容都是一个属性,因此,进行变异操作的一种方法是添加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函数时类似的工作:
public class AmountLabel extends Label {
public AmountLabel(String text) {
super(text);
textProperty().addListener(observable ->
System.out.println("Amount invalidated.")
);
}
}
回答其他问题
因此,在更改侦听器中,我将在设置任何掩码之后设置适当的值吗?
好吧,你可以,我以前做过。我不确定这样做是否是最佳做法(尽管我不知道其他一般的处理方式)。我确实记得JavaFX属性设计器在某个论坛上说过,他们并未真正设计用于更改侦听器中更新的属性机制,所以我想不能保证。
我遇到了在更改侦听器中更改WebView的location属性导致线程问题的问题,但是由于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,将包括以下功能:
RT-14000 Add Formatted TextField control
另一个相关的open-jfx实现项目是:
RT-37785 Provide some useful TextInputControl.Formatter implementations
那不是当前的9,但是一旦实现,就可以帮助提供您所要求的进一步的具体用例,并且开发人员在票证上指出“我们相信提供8u40的示例代码就足够了”。
第三方JideFX library includes a FormattedTextField class。
有关JavaFX API中的内容为何最终的一些背景信息
Quote from Richard Bair,首席JavaFX开发人员:
安全为一。您可以对非期末班做恶事!那只是一条一般规则(这就是为什么我们通常希望使一切都可以最终完成)。在这种特定情况下,可能没有关系。
一条建议
您可能想要做的不是代替诸如文本输入格式器之类的getter方法,而是要为格式掩码与未格式化的值文本与已格式化的值文本使用不同的API。我认为这可能是将格式化的JavaFX TextField添加到Java 8u40的过程。
看一下EasyBind
第三方EasyBind库可能有一些不错的方法来处理您要实现的模式。
关于java - 自JavaFX设置程序/获取程序是最终的最佳实践?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28056557/