JavaFX 11无法编辑的ComboBox无法在组合项目列表外部正确显示值 [英] JavaFX 11 uneditable ComboBox not displaying values outside combo items list properly

查看:69
本文介绍了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 (例如,在弹出列表中通过键盘取消选择先前的非null值),则可以正确显示新的非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.

更新

经过进一步的挖掘,它看起来像是回归懒惰(不是我的措辞,尽管喜欢它)修复.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天全站免登陆