Selezionare un elemento in una ComboBox con la tastiera in JavaFX

Mattepuffo's logo
Selezionare un elemento in una ComboBox con la tastiera in JavaFX

Selezionare un elemento in una ComboBox con la tastiera in JavaFX

Se usate Swing e il componente JComboBox, avrete notato che potete selezionare un elemento usando la tastiera.

In pratica, dopo aver impostato il focus sulla JComboBox, scrivete sulla tastiera per cercare l'elemento che vi serve.

Questo comportamento non è presente sul relativo componente ComboBox di JavaFX.

Mi piacerebbe molto sapere il perchè....

Comunque ho trovato questa classe che può ovviare al problema:

import com.sun.javafx.scene.control.skin.ComboBoxListViewSkin;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class KeyComboListener implements EventHandler<KeyEvent> {

    private ComboBox cb;
    private StringBuilder sb = new StringBuilder();

    public KeyComboListener(ComboBox cb) {
        this.cb = cb;
        this.cb.setOnKeyReleased(KeyComboListener.this);
        this.cb.addEventFilter(KeyEvent.KEY_RELEASED, event -> {
            if (event.getCode() == KeyCode.ESCAPE && sb.length() > 0) {
                sb.delete(0, sb.length());
            }
        });
        this.cb.focusedProperty().addListener((ChangeListener) 
		(observable, oldValue, newValue) -> {
            if (newValue instanceof Boolean && !((Boolean) newValue).booleanValue())
                sb.delete(0, sb.length());
            else {
                ListView lv = ((ComboBoxListViewSkin) KeyComboListener
				.this.cb.getSkin()).getListView();
                lv.scrollTo(lv.getSelectionModel().getSelectedIndex());
            }
        });
        this.cb.setOnMouseClicked(event -> {
            ListView lv = ((ComboBoxListViewSkin) KeyComboListener.this.
			cb.getSkin()).getListView();
            lv.scrollTo(lv.getSelectionModel().getSelectedIndex());
        });
    }

    @Override
    public void handle(KeyEvent event) {
        if (event.getCode() == KeyCode.DOWN || event.getCode() == KeyCode.UP 
		|| event.getCode() == KeyCode.TAB) {
            return;
        } else if (event.getCode() == KeyCode.BACK_SPACE && sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        } else {
            sb.append(event.getText());
        }

        if (sb.length() == 0)
            return;

        boolean found = false;
        ObservableList items = cb.getItems();
        for (int i = 0; i < items.size(); i++) {
            if (event.getCode() != KeyCode.BACK_SPACE && items.get(i).toString()
			.toLowerCase().startsWith(sb.toString().toLowerCase())) {
                ListView lv = ((ComboBoxListViewSkin) cb.getSkin()).getListView();
                lv.getSelectionModel().clearAndSelect(i);
                lv.scrollTo(lv.getSelectionModel().getSelectedIndex());
                found = true;
                break;
            }
        }

        if (!found && sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
    }
}

A questo punto dovete solo riempire la ComboBox, e richiamare questa classe:

List<Author> listAuthors = // RIEMPI LISTA
ObservableList<Author> authors = FXCollections.
observableArrayList(listAuthors);
comboAuthor.setItems(authors);
comboAuthor.setCellFactory(new ComboListCell<Author>());
new KeyComboListener(comboAuthor);

E il gioco è fatto!

Enjoy!


Condividi

Commentami!