Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX autocomplete ComboBox drop-down size

I have to create an auto fill ComboBox based on user input.

My code goes like this:

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

the AutoCompleteComboBoxListener is taken from this answer.

With this autocomplete works fine. I faced a problem in list size,

Run the application and click on the ComboBox drop down to see popup size.

  • Type ANDRE in the combo box(which will show ANDRE option in popup).Now delete all characters.(by backspace)
  • Now the populated list shrinked to one entry size with scroll bar.
  • Click on the combo box drop down again to get the full size list.

How can I make the list size according to content?

like image 818
user3164187 Avatar asked Mar 12 '23 11:03

user3164187


2 Answers

Not exactly a "list size according to content" (which would be awful if the number of items is too large to fit on the screen, BTW), but you can specify the minimum height of the ListView shown in the popup using CSS.

This ensures the popup size never becomes too small. Even if the number of items is small, this will leave some "empty space" at the bottom of the ListView:

.combo-box .combo-box-popup > .list-view {
    -fx-min-height: 200;
}
like image 151
fabian Avatar answered Mar 29 '23 09:03

fabian


This is because the comboBox.hide(); method is not called (the drop-down list is automatically updated on show).

You can improve the listener as:

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

}

This update will ensure, that the drop-down list will be hidden and re-shown every time the search String has been changed.

like image 28
DVarga Avatar answered Mar 29 '23 09:03

DVarga