Compartilhando: Classe AutoCompleteComboBox para JavaFX

Galera, como eu precisei, acredito que outros irão precisar, então estou compartilhando a classe que faz o AutoComplete num JFXComboBox utilizando JavaFX.

1-Adicione uma nova classe no pacote util de seu projeto com nome “utilAutoCompleteComboBox”.

2-Cole o código abaixo:

package informe o caminho do pacote aqui;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class utilAutoCompleteComboBox<T> implements EventHandler<KeyEvent> {

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

    public utilAutoCompleteComboBox(final ComboBox comboBox) {
        this.comboBox = comboBox;
        sb = new StringBuilder();
        data = comboBox.getItems();

        this.comboBox.setEditable(true);
        this.comboBox.setOnKeyPressed(new EventHandler<KeyEvent>() {

            @Override
            public void handle(KeyEvent t) {
                comboBox.hide();
            }
        });
        this.comboBox.setOnKeyReleased(utilAutoCompleteComboBox.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;
        } else if (event.getCode() == KeyCode.BACK_SPACE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        } else if (event.getCode() == KeyCode.DELETE) {
            moveCaretToPos = true;
            caretPos = comboBox.getEditor().getCaretPosition();
        }

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

        ObservableList list = FXCollections.observableArrayList();
        for (int i = 0; i < data.size(); i++) {
            if (data.get(i).toString().toLowerCase().startsWith(utilAutoCompleteComboBox.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;
    }
}

3-Lá no controller da tela que você tem o JFXComboBox você inclui este método abaixo:

//Método que popula o JFXComboBox usuário da tela de login e implementa o AutoComplete
    private void carregaUsuario() {
        try {
            //Lista que receberá os dados do BD (Usuários)
            //Para alimentar o JFXComboBox usuário
            List<String> lista = new ArrayList<>();
            Connection conn = dbConexao.getConnection();
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("SELECT username FROM usuarios ORDER BY username ASC");

            if (rs.next()) {//Caso puxar dados do BD
                while (rs.next()) {//Popula o comboBox
                    //Passa por todos os registros e adiciona na lista
                    lista.add(rs.getString("username"));

                    //Adiciona a lista ao JFXComboBox
                    SEU_COMBOBOX_AQUI.setItems(FXCollections.observableArrayList(lista));
                    
                    //Implementa o AutoComplete utilizando a classe utilAutoCompleteComboBox
                    new utilAutoCompleteComboBox<>(SEU_COMBOBOX_AQUI);
                }
            } else {//Caso não puxar dados do BD emite a msg de erro
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setTitle("Alerta!");
                alert.setHeaderText("O servidor está offline");
                alert.setContentText("Tente novamente ou entre em contato com o suporte técnico");
                alert.initStyle(StageStyle.UNDECORATED);
                alert.showAndWait();//Emite o alerta de erro servidor
                SEU_COMBOBOX_AQUI.requestFocus();
            }
            dbConexao.close((com.mysql.jdbc.Connection) conn, st, rs);
        } catch (Exception ex) {
            ex.printStackTrace();
            System.err.println("ERR" + ex);
        }
    }

4-No mesmo controller, dentro do método default “initialize” você vai chamar o método acima “carregaUsuario();”, assim que a tela for iniciada vai popular o JFXComboBox e implementar o AutoComplete:

@Override
    public void initialize(URL url, ResourceBundle rb) {
        //Chamada dos métodos
        carregaUsuario();//Popula o JFXComboBox usuário com AutoComplete
    }

Fim! :+1:t2:

Cara, criei uma conta aqui só para te dizer muito obrigado! Eu estava procurando justamente isso.

Amigo, você sabe como definir uma máscara de telefone para uma ComboBox?