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

时间:2015-09-17 00:18:27

标签: java combobox datepicker javafx-8

我们已广泛搜索此论坛和网站,但未找到与此问题相关的任何内容,因此我不得不在此处发布此问题...

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

在u51下运行,你可以在DatePicker和tab中输入一个日期,如12/30/1970,到下一个U.I.元素和数据将自动保存,如果日期绑定到年龄计算TextField,则年龄将更新。可编辑的ComboBox元素也是如此。但是在u60下运行时,用户必须在DatePicker或可编辑的ComboBox上更改数据后按 ENTER ,否则不会保存数据。跳到下一个U.I.在U.I.之外的元素或鼠标点击元素和数据丢失,取而代之前在编辑之前保存在该元素中的内容。

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

最后是一个解决方案,可能是一个事件处理程序的形式,可以模拟一个' ENTER'在失去这些元素的焦点之前按键?

提前感谢您的考虑。

2 个答案:

答案 0 :(得分:2)

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

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

  • 是:转发组合接收的所有keyEvent textField
  • 是:处理并使用基础皮肤中的ENTER。此实现手动将输入文本从字段提交到组合的值。

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

public class MyComboSkin<T> extends ComboBoxListViewSkin<T> {

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

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

// 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) 
BTW:我认为核心中的新实现相当脏 - 所有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,所以任何解决方法都可能是短暂的,选择一次或其他并且根据需要进行肮脏可能是一个品味问题: - )

答案 1 :(得分:0)

这是我的解决方法:

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

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