Java 8 DatePicker 和可编辑的 ComboBox 行为在 8u51 和 8u60 之间发生变化

Posted

技术标签:

【中文标题】Java 8 DatePicker 和可编辑的 ComboBox 行为在 8u51 和 8u60 之间发生变化【英文标题】:Java 8 DatePicker and editable ComboBox behavior change between 8u51 and 8u60 【发布时间】:2015-12-13 18:09:37 【问题描述】:

我们已经广泛搜索了这个论坛和网络,但没有找到与这个问题相关的任何东西,所以我觉得有必要在这里发布这个问题......

我们观察到在 Java 8 u51 和 u60 版本之间,JavaFX8 DatePicker 和可编辑 ComboBox 元素的功能发生了重大的行为变化。

在 u51 下运行,您可以在 DatePicker 中输入诸如 1970 年 12 月 30 日之类的日期,然后通过 Tab 转到下一个 UI。元素和数据将自动保存,如果日期绑定到年龄计算 TextField 年龄将更新。可编辑的 ComboBox 元素也是如此。但是在 u60 下运行,用户必须在 DatePicker 或可编辑 ComboBox 上更改数据后按 ENTER,否则不会保存数据。跳转到下一个 U.I.元素或在 UI 之外单击鼠标。元素和数据丢失,替换为在编辑之前保存在该元素中的内容。

所以我的问题是,有没有其他人注意到这种关键的行为变化,如果有的话,是否认为这是 u60 中的一个错误或 Oracle 出于某种原因故意采取的方向?

最后是否有一种变通方法,也许是以事件处理程序的形式,可以在这些元素失去焦点之前模拟“ENTER”键按下?

提前感谢您的考虑。

【问题讨论】:

您会发现通过发布可重现的示例更容易获得帮助。询问是否有人遇到过同样的问题会大大降低您获得好答案的机会。如果您发布极简代码以便我们可以重现,那么任何愿意提供帮助的人都会遇到同样的问题(通过尝试您的代码)并能够帮助您找到解决方法。 【参考方案1】:

ComboBoxPopupControl 的实现(实际上是所有类似组合控件的相关基础皮肤)在 u40 和 u60 之间的某个地方发生了变化:文本字段 - 包括所有内部布线 - 是从具体皮肤中拉出的(如 fi ComboBoxListViewSkin)进入基地。

除了这种技术性之外,ENTER 的处理程序也发生了变化:

是:将组合接收到的所有 keyEvents 转发到 文本字段 是:处理和消耗基础皮肤中的ENTER。此实现手动将字段中的输入文本提交给组合的值。

脏(!因为需要访问内部包 com.sun.whatever.skin)出路是自定义皮肤,它监听 focusProperty 并调用提交方法,类似于:

public class MyComboSkin<T> extends ComboBoxListViewSkin<T> 

    public MyComboSkin(ComboBox<T> comboBox) 
        super(comboBox);
        getSkinnable().focusedProperty().addListener((source, ov, nv) -> 
            if (!nv) 
                setTextFromTextFieldIntoComboBoxValue();
            
        );
    

应用自定义皮肤的优点是可以通过添加样式表在每个场景中应用一次:

// defining the skin in a css mycomboskin.css 
.combo-box 
    -fx-skin: "mypackage.MyComboSkin";


// apply to a scene
String commitCSS = getClass().getResource("mycomboskin.css").toExternalForm();
scene.getStylesheets().add(commitCSS);

// or to the application (using internal api again ;-)
StyleManager.getInstance().addUserAgentStylesheet(commitCSS) 

顺便说一句:我认为核心中的新实现相当脏 - 所有 keyBindings 应该 在 XXBehaviour 中处理,或者留给较低级别​​的子项(如 textField 本身)。行为变化(针对 8u45 验证)可能被视为错误。


更新

另一种技巧是在组合的编辑器上使用 TextFormatter 并将它的 valueProperty 双向绑定到组合的 valueProperty,例如:

TextFormatter formatter = 
        new TextFormatter<>(comboBox.getConverter());
comboBox.getEditor().setTextFormatter(formatter);
comboBox.valueProperty().bindBidirectional(formatter.valueProperty());

这确实有效,因为格式化程序保证提交 - 也就是:将其自己的值同步到 textField 的文本 - 在 focusLost 上(更多细节在类似的requirement for Spinner)请注意,这种方法的副作用是文本是提交在下拉菜单中的导航上,这可能会或不能接受,具体取决于上下文。此外,与专用解决方法相比,它更多的是使用 TextFormatters 进行试验 - 需要与 other solution by Scott 中的解决方法相同的每个实例操作。


bug 已在 jdk9 中修复并向后移植 8u72,因此任何解决方法都希望是短暂的,选择一次或其他并根据需要尽可能脏可能是个人喜好问题 :-)

【讨论】:

对我来说,8u73 似乎仍然存在问题:-( 发现在8u74已经修复了。 然而,看起来可编辑的 Spinner 也有同样的问题 :-( @wzberger - 你是说微调器问题没有解决吗?那将是......糟糕......去再次站起来:-) 我会在大约 100 公斤的活重下,从桌面上跳下来,尽我所能 ;-) 表示已经提交了错误报告。【参考方案2】:

这是我的解决方法:

    combo.getEditor().focusedProperty().addListener((obs, old, isFocused) ->  
        if (!isFocused)  
            combo.setValue(combo.getConverter().fromString(combo.getEditor().getText()));
         
    ); 

正如官方bug report 中指出的那样,您可能需要检查该值是否已设置以避免再次调用它的任何潜在副作用。

【讨论】:

以上是关于Java 8 DatePicker 和可编辑的 ComboBox 行为在 8u51 和 8u60 之间发生变化的主要内容,如果未能解决你的问题,请参考以下文章

在线文档编辑器的使用和数据字典(ueditor编辑器/my97datepicker日期控件)

如何使用 Expression Blend 在 WPF 中编辑 DatePicker 的水印

Android中关闭DatePicker和NumberPicker等Picker类的可编辑模式

编辑 WPF 工具包以仅获取 DatePicker

如何使用 DatePicker 编辑我的日期?

在编辑模式下,Material-ui/DatePicker 中未填充日期