JavaFX 11 不可编辑的 ComboBox 未正确显示组合项列表之外的值 [英] JavaFX 11 uneditable ComboBox not displaying values outside combo items list properly

查看:27
本文介绍了JavaFX 11 不可编辑的 ComboBox 未正确显示组合项列表之外的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 JaxaFX 11 ComboBox 时遇到问题(似乎在 JavaFX 8 中它工作正常).

I have troubles with JaxaFX 11 ComboBox (it seems that in JavaFX 8 it works OK).

对于不可编辑组合,即在按钮单元中显示所选值(不在可编辑文本框中),如果新值不显示,则不显示任何值(按钮单元可能被视为空")包含在组合的项目列表中,只有一个例外:

For uneditable combo, i.e. displaying the selected value in buttoncell (not in editable textbox), no value is displayed (buttoncell probably considered "empty"), if the new value is not included in the combo's items list, with one exception only:

如果前一个值为 null(例如,在弹出列表中通过键盘取消选择前一个非空值),则正确显示新的非空值.

If the previous value is null (I e.g. deselect the previous non null value by keyboard in popup list), the new non null value is displayed correctly.

查看一个简单的代码来重现问题.最初,组合值为 null.按 按钮设置项目列表之外的值.显示正常.然后从弹出窗口中选择一些值.再次尝试按下按钮.现在组合保持为空,尽管组合值已更改.

See a simple code to reproduce the problem. Initially, the combo value is null. Press the button to set a value outside items list. It is displayed OK. Then choose some value from the popup. Try again to press the button. Now the combo stays empty, although the combo value was changed.

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ComboTest extends Application {
    private ComboBox<String> testCombo;

    @Override public void start(Stage primaryStage) {
        Button btn = new Button("Set test value outside list");
        btn.setOnAction(e -> {
            testCombo.setValue("test value outside list");
        });

        testCombo = new ComboBox<>(FXCollections.observableArrayList(
                "Option 1", "Option 2", "Option 3"
        ));
        testCombo.setPromptText("null now!");

        TextField valueTextField = new TextField();
        testCombo.valueProperty().addListener((ob, ov, nv) -> {
            valueTextField.setText("combo value: " + nv);
        });

        VBox root = new VBox(5);
        root.setPadding(new Insets(5));
        root.getChildren().addAll(btn, testCombo, valueTextField);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Test Combo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

我错过了什么吗?我找不到任何解决方法.我试图调试,但找不到答案.似乎首先设置了正确的文本,但随后又将其删除.

Am I missing something? I was not able to find any workaround. I tried to debug, but could not find the answer. Is seems first the correct text is set, but then it is erased again.

(JDK 11.0.2、JavaFX 11.0.2、Netbeans 10)

(JDK 11.0.2, JavaFX 11.0.2, Netbeans 10)

推荐答案

对我来说看起来像是一个错误:由于某种原因,displayNode(即 buttonCell 的内容)在设置非包含值时未更新,而包含值被选中.仅通过 ComboBoxBaseSkin 上的公共 api 访问 displayNode 会触发正确的设置.

Looks like a bug for me: for some reason the displayNode (that is the content of the buttonCell) is not updated on setting an uncontained value while a contained value is selected. Merely accessing the displayNode via its public api on ComboBoxBaseSkin triggers the correct setting.

要查看它的更新,请将以下几行添加到您的示例中,并在未显示未包含的值后单击该按钮:

To see it updating, add the following lines to your example and click that Button after the uncontained value is not showing:

Button display = new Button("getDisplayNode");
display.setOnAction(e -> {
    ((ComboBoxBaseSkin) testCombo.getSkin()).getDisplayNode();
});

为了解决这个问题,我们可以扩展组合的皮肤并在每个布局阶段强制更新:

To hack around the issue, we can extend the combo's skin and force the update in each layout pass:

public static class MyComboBoxSkin<T> extends ComboBoxListViewSkin<T> {

    public MyComboBoxSkin(ComboBox<T> control) {
        super(control);
    }

    @Override
    protected void layoutChildren(double x, double y, double w, double h) {
        super.layoutChildren(x, y, w, h);
        // must be wrapped inside a runlater, either before or after calling super
        Platform.runLater(this::getDisplayNode);
    }

}

用法:

testCombo = new ComboBox<>(FXCollections.observableArrayList("Option 1", "Option 2", "Option 3")) {
    @Override
    protected Skin<?> createDefaultSkin() {
        return new MyComboBoxSkin<>(this);
    }
};

注意:皮肤实现大量使用了多个布尔脏标志,在这种特殊情况下,这些标志似乎具有破坏性的交互作用(不幸的是,不明白具体如何).使用 Platform.runlater 延迟访问似乎有效.

Note: the skin implementation makes heavy use of multiple boolean dirty flags, which seem to interact destructively in this particular case (don't understand how exactly, unfortunately). Delaying the access with a Platform.runlater seems to work.

更新

经过进一步挖掘,它看起来像是由lazy-dirty(不是我的措辞,虽然喜欢:) 修复.Tom 提供的自定义单元实现效果很好.

after some further digging, it looks like being a regression introduced by a lazy-dirty (not my wording, like it though :) fix. The custom cell implementation provided by Tom works nicely.

这篇关于JavaFX 11 不可编辑的 ComboBox 未正确显示组合项列表之外的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆