JavaFX 自动完成组合框下拉大小

Posted

技术标签:

【中文标题】JavaFX 自动完成组合框下拉大小【英文标题】:JavaFX autocomplete ComboBox drop-down size 【发布时间】:2016-12-16 17:31:06 【问题描述】:

我必须根据用户输入创建一个自动填充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 取自 answer。

使用此自动完成功能可以正常工作。我遇到了列表大小的问题,

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

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

如何根据内容制作列表大小?

【问题讨论】:

@Reimeus 如何在这种情况下使用 sizeToScene() 方法。 【参考方案1】:

这是因为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;
    


此更新将确保每次更改搜索 String 时下拉列表将被隐藏并重新显示。

【讨论】:

这可能会产生奇怪的视觉效果,如果弹出窗口只是消失一瞬间...... 是的,我知道。我猜原来的那个已经打算使用这种隐藏显示机制:comboBox.hide() on keyPress。我将搜索如何将下拉列表调整为内容而不会出现这种“闪烁”。【参考方案2】:

不完全是 “根据内容的列表大小”(如果项目数量太大而无法在屏幕上显示,这会很糟糕,顺便说一句),但您可以指定使用 CSS 弹出的ListView

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

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

【讨论】:

这是一个没有我想象的那么糟糕的解决方案。谢谢,@f***。【参考方案3】:

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

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

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

默认情况下,双击清除值。还有一些其他有用的功能。您可以添加额外的列或字形,挑出特定项目,将项目默认更改为字符串表示...

ComboBoxCustomizer.create(comboBox)
                  .autocompleted(items)
                  .overrideToString(o -> "planet: " + o)
                  .multyColumn(o -> Arrays.asList("column 2", "column 3"))
                  .emphasized(o -> o.endsWith("s"))
                  .customize();

【讨论】:

以上是关于JavaFX 自动完成组合框下拉大小的主要内容,如果未能解决你的问题,请参考以下文章

javafx 组合框下拉菜单从屏幕边缘出来

自动完成下拉菜单未正确显示

每个单词下方的jQuery-ui自动完成下拉菜单

对于第一个句点之后的参数,自动完成/下拉框

为啥动态值没有填充在自动完成组合框中?

使用下拉列表在 Java 中创建一个自动完成文本框