作为独立元素,this解决方案可以正常工作。

但是在自定义ListCell(从ComboBoxListCell来源进行镜像)中,有时会给出:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at com.sun.javafx.scene.control.skin.ComboBoxPopupControl.positionAndShowPopup(ComboBoxPopupControl.java:100)
at com.sun.javafx.scene.control.skin.ComboBoxPopupControl.show(ComboBoxPopupControl.java:74)
at com.sun.javafx.scene.control.skin.ComboBoxBaseSkin.handleControlPropertyChanged(ComboBoxBaseSkin.java:115)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.handleControlPropertyChanged(ComboBoxListViewSkin.java:245)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$2.call(BehaviorSkinBase.java:189)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$2.call(BehaviorSkinBase.java:187)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:176)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
at javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:178)
at javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl.access$100(ReadOnlyBooleanWrapper.java:148)
at javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:144)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:143)
at javafx.scene.control.ComboBoxBase.setShowing(ComboBoxBase.java:202)
at javafx.scene.control.ComboBoxBase.show(ComboBoxBase.java:407)


似乎ComboBox的show()方法可以在JavaFX代码内生成NPE。

自定义ComboBoxListCell仅在startEdit()中有所不同:

@Override public void startEdit() {
    if (! isEditable() || ! getListView().isEditable()) {
        return;
    }

    if (comboBox == null) {
        comboBox = createComboBox(this, items, converterProperty());

        //The only special string
        handler = new AutoCompleteComboBoxListener<>(comboBox);

        comboBox.editableProperty().bind(comboBoxEditableProperty());
    }

    comboBox.getSelectionModel().select(getItem());

    super.startEdit();

    if (isEditing()) {
        setText(null);
        setGraphic(comboBox);
    }
}


提供NPE的AutoCompleteComboBoxListener代码:

@Override
public void handle(KeyEvent event) {

    if(event.getCode() == KeyCode.UP) {
        caretPos = -1;
        moveCaret(comboBox.getEditor().getText().length());
        return;
    } else if(event.getCode() == KeyCode.DOWN) {
        if(!comboBox.isShowing()) {
            comboBox.show();
        }
        caretPos = -1;
        moveCaret(comboBox.getEditor().getText().length());
        return;
    } else if(event.getCode() == KeyCode.BACK_SPACE) {
        moveCaretToPos = true;
        caretPos = comboBox.getEditor().getCaretPosition();
    } else if(event.getCode() == KeyCode.DELETE) {
        moveCaretToPos = true;
        caretPos = comboBox.getEditor().getCaretPosition();
    }

    if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT
            || event.isControlDown() || event.getCode() == KeyCode.HOME
            || event.getCode() == KeyCode.END || event.getCode() == KeyCode.TAB) {
        return;
    }

    ObservableList list = FXCollections.observableArrayList();
    for (int i=0; i<data.size(); i++) {
        if(data.get(i).toString().toLowerCase().startsWith(
            AutoCompleteComboBoxListener.this.comboBox
            .getEditor().getText().toLowerCase())) {
            list.add(data.get(i));
        }
    }
    String t = comboBox.getEditor().getText();

    comboBox.setItems(list);
    comboBox.getEditor().setText(t);
    if(!moveCaretToPos) {
        caretPos = -1;
    }
    moveCaret(t.length());
    if(!list.isEmpty()) {

        //This gives NPE inside JavaFX API
        comboBox.show();
    }
}

最佳答案

好的,问题是setItems将当前选择跳过为-1,然后ListCell将该事实视为需要提交新值(空)(如果当前选择!= -1)。在提交之后,comboBox不会显示任何内容,因为它处于非编辑状态。

因此,这是一个设计问题,而不是错误。如果没有特别注意,ComboBoxListCell代码只是无法即时更改项目。

10-04 14:53