在用户明确按下Enter键之前,似乎Spinner控件不会更新手动键入的值。因此,他们可以键入一个值(不按Enter键)以退出控件,然后提交表单,并且 Spinner 中显示的值不是 Spinner 的值,而是旧值。
我的想法是向丢失的焦点事件添加一个侦听器,但是我看不到获得对输入值的访问的方法吗?
spinner.focusedProperty().addListener((observable, oldValue, newValue) ->
{
//if focus lost
if(!newValue)
{
//somehow get the text the user typed in?
}
});
这是奇怪的行为,似乎违反了GUI微调控件的约定。
不幸的是,Spinner的表现不符合预期:在大多数操作系统中,它应该将编辑后的值提交给失去的焦点。更不幸的是,它没有提供任何配置选项来轻松使其表现出预期的效果。
因此,我们必须手动将侦听器中的值提交给focusedProperty。从好的方面来说,Spinner已经有这样做的代码-它是私有的,但是我们必须对它进行c&p
/**
* c&p from Spinner
*/
private <T> void commitEditorText(Spinner<T> spinner) {
if (!spinner.isEditable()) return;
String text = spinner.getEditor().getText();
SpinnerValueFactory<T> valueFactory = spinner.getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
}
// useage in client code
spinner.focusedProperty().addListener((s, ov, nv) -> {
if (nv) return;
//intuitive method on textField, has no effect, though
//spinner.getEditor().commitValue();
commitEditorText(spinner);
});
请注意,有一种方法
textField.commitValue()
我本来希望...好吧...提交该值,但没有任何效果。它已实现(最终!),以更新textFormatter的值(如果有)。即使你使用textFormatter进行验证,在Spinner中也不起作用。可能是某些内部侦听器丢失或 Spinner 尚未更新到相对较新的api-但是没有挖掘。
更新
在使用TextFormatter进行更多操作时,我注意到格式化程序可以保证对focusLost进行提交:
当控件失去焦点或被提交时,将更新该值(仅TextField)
确实如文档所述工作,以便我们可以在格式化程序的valueProperty中添加一个侦听器,以便在提交值时得到通知:
TextField field = new TextField();
TextFormatter fieldFormatter = new TextFormatter(
TextFormatter.IDENTITY_STRING_CONVERTER, "initial");
field.setTextFormatter(fieldFormatter);
fieldFormatter.valueProperty().addListener((s, ov, nv) -> {
// do stuff that needs to be done on commit
} );
触发提交:
回到 Spinner :我们可以使用格式化程序值的这种commit-on-focusLost行为来强制对spinnerFactory的值进行提交。就像是
// normal setup of spinner
SpinnerValueFactory factory = new IntegerSpinnerValueFactory(0, 10000, 0);
spinner.setValueFactory(factory);
spinner.setEditable(true);
// hook in a formatter with the same properties as the factory
TextFormatter formatter = new TextFormatter(factory.getConverter(), factory.getValue());
spinner.getEditor().setTextFormatter(formatter);
// bidi-bind the values
factory.valueProperty().bindBidirectional(formatter.valueProperty());
需要注意的是编辑(无论是打字或以编程方式替换/追加/粘贴文本),并没有引发提交-所以,如果提交上文本变化需要此不能使用。
对于那些想知道为什么尽管按Enter键后微调器仍未更新的人来说,您可能正在使用:一个ChangeListener -仅在值发生实际更改时才激活,而JavaFX有时似乎出错了。尝试使用InvalidationListener。
@kleopatra希望网站将有关此评论的信息通知您,我对以下来自Sergio的回答有疑问。您对此有什么想法吗?似乎是一个简短而甜蜜的解决方案,感觉太好了,难以置信。它仅比您新一年,如果真是太好了,我希望它到现在能超过您的答案。Sergio的答案是否存在需要注意的问题?还是人们在到达您的解决方案后立即停止滚动?当我尝试根据该答案标记您时,我认为它不起作用。
@pateksan已经有一段时间没有对此进行研究了(忘记了同时存在的潜在错误是否已修复)-另一个答案是基于未指定实现细节的黑客攻击。这种行为有点出乎意料,IMO,我们也可以在编辑时拒绝inc / dec。但是,然后,如果没有提供任何东西,我们就必须去做所有的工作:)
@kleopatra,谢谢。我还有一个问题(对不起,如果让您陷入一个老问题):当您说我们在编辑时也可以拒绝inc / dec时,我有点困惑。拒绝inc / dec似乎与OP问题无关。这是塞尔吉奥代码的副作用吗?还是实现OP原始目标的另一种方法?另外,我还是新手,但是如果您将其置于Sergio的回答而不是您的回答下,那么您的评论(仅一个小时前,高于此的评论)可能对所有人有用-很抱歉,建议您这样做还有2 ^ 8代表的人。
@pateksan简短(也是最后一个)答案:是的-对不起,这变得太离题了-要学习所有关于引用的知识,通读有关弱引用/强引用的Java基础教程,并将学到的知识应用到此上下文中(fi通过思考这里的参考路径,编写测试,在卡住时问一个问题..::)玩得开心!