JavaFX自动完成ComboBox下拉菜单大小

4

我需要创建一个基于用户输入的自动填充ComboBox

我的代码如下:

public class JavaFXApplication1 extends Application {

    @Override
    public void start(Stage primaryStage) {
        ComboBox<String> combo = new ComboBox<>();
        ObservableList<String> list = FXCollections.observableArrayList();
        list.add("A");
        list.add("AND");
        list.add("ANDR");
        list.add("ANDRE");
        list.add("B");
        list.add("BP");
        list.add("BPO");
        combo.setItems(list);
        new AutoCompleteComboBoxListener(combo);

        StackPane root = new StackPane();
        root.getChildren().add(combo);

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

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

AutoCompleteComboBoxListener 是从这个 答案 中获取的。

使用此自动完成功能正常。我在列表大小方面遇到了问题,

运行应用程序并单击 ComboBox 下拉以查看弹出窗口大小。

  • 在组合框中键入 ANDRE(将在弹出窗口中显示 ANDRE 选项)。现在删除所有字符。(通过退格键)
  • 现在填充的列表缩小为一个条目大小,带有滚动条。
  • 再次单击下拉列表以获得完整大小列表。

如何根据内容调整列表大小?


@Reimeus,我该如何在这种情况下使用sizeToScene()方法? - user3164187
3个回答

4

并不是根据内容大小来确定列表大小(如果条目数量太多无法适应屏幕大小,那将是糟糕的),但是您可以使用CSS指定在弹出窗口中显示的ListView的最小高度。

这样可以确保弹出窗口的大小永远不会变得过小。即使条目数量很少,也会在ListView底部留下一些“空白空间”:

.combo-box .combo-box-popup > .list-view {
    -fx-min-height: 200;
}

这个解决方案比我想象中要好一些。谢谢@fabian。 - Brad Turek

3
这是因为没有调用comboBox.hide();方法(下拉列表在显示时会自动更新)。
您可以改进监听器如下:
public class AutoCompleteComboBoxListener<T> implements EventHandler<KeyEvent> {

    private ComboBox<T> comboBox;
    private ObservableList<T> data;
    private boolean moveCaretToPos = false;
    private int caretPos;

    public AutoCompleteComboBoxListener(final ComboBox<T> comboBox) {
        this.comboBox = comboBox;
        data = comboBox.getItems();

        this.comboBox.setEditable(true);
        this.comboBox.setOnKeyReleased(AutoCompleteComboBoxListener.this);
    }

    @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;
        } 

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

        comboBox.hide();

        if(event.getCode() == KeyCode.BACK_SPACE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        } else if(event.getCode() == KeyCode.DELETE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        }



        ObservableList<T> 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()) {
            comboBox.show();
        }
    }

    private void moveCaret(int textLength) {
        if(caretPos == -1) 
            comboBox.getEditor().positionCaret(textLength);
        else 
            comboBox.getEditor().positionCaret(caretPos);

        moveCaretToPos = false;
    }

}

此更新将确保每次更改搜索字符串后,下拉列表都会被隐藏并重新显示。


这可能会产生奇怪的视觉效果,如果弹出窗口只消失了一瞬间... - fabian
是的,我知道。原本就打算使用隐藏-显示机制了吧:在keyPress事件中调用comboBox.hide()。我会搜索一下如何在没有“闪烁”的情况下将下拉列表调整为适应内容大小。 - DVarga

1

我建议尝试来自小型实用程序库jalvafx的解决方案。

List<String> items = Arrays.asList("Mercury", 
                                   "Venus", 
                                   "Earth", 
                                   "Mars", 
                                   "Jupiter", 
                                   "Saturn", 
                                   "Neptune");

ComboBoxCustomizer.create(comboBox)
                  .autocompleted(items)
                  .customize();

默认情况下,双击清除值。还有一些其他有用的功能。您可以添加额外的列或字形,单独指定特定项,更改项的默认 toString 表示...
ComboBoxCustomizer.create(comboBox)
                  .autocompleted(items)
                  .overrideToString(o -> "planet: " + o)
                  .multyColumn(o -> Arrays.asList("column 2", "column 3"))
                  .emphasized(o -> o.endsWith("s"))
                  .customize();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接