ComboBox Autocomplete triggers upon selecting entries from dropdown list, not just typing

Issue #736 new
Peter Trefonas
created an issue

This is irritating and shouldn't happen. Autocomplete should only trigger when typing, not when using the mouse or arrow keys to select an entry from a combo list.

Using it like this: myCombo.setEditable(true); TextFields.bindAutoCompletion(myCombo.getEditor(), myCombo.getItems());

Comments (11)

  1. Peter Trefonas reporter

    Hey Samir,

    Sorry for not including a coding example! I was considering the most basic scenario. Here is an example showing the issue.

    So in this example, if you type "O" or "option" all three options appear and can be selected properly. If you type "2", only "Option 2" appears. This is good. If you use the mouse or arrow keys to select an option after pressing the little down arrow on the right side of a combo box, an additional drop down list appears, even though you have already selected from the list of options. This is bad.

    import javafx.collections.ObservableList;
    import javafx.collections.FXCollections;
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.scene.control.ComboBox;
    import javafx.stage.Stage;
    import org.controlsfx.control.textfield.TextFields;
    
    public class App extends Application {
      public static void main(String[] args) {
        launch(args);
      }
    
      @Override
      public void start(Stage stage) throws Exception {
        ComboBox<String> myCombo = new ComboBox<String>();
        ObservableList<String> options = 
          FXCollections.observableArrayList("Option 1","Option 2","Option 3");
        myCombo.setItems(options);
        myCombo.setEditable(true);
        TextFields.bindAutoCompletion(myCombo.getEditor(), myCombo.getItems());
        stage.setScene(new Scene(new Pane(myCombo)));
        stage.setMinWidth(200);
        stage.setMinHeight(200);
        stage.show();
      }
    }
    
  2. Samir Hadzic

    Allright, thanks.

    The problem must come from the fact that we do not see we already selected something and we must not show the drop down list. I'll investigate. If you have any ideas on how to fix that, don't hesitate to submit a pull request or some code in here.

  3. Md.Al-Helal

    Thank you , Peter Trefonas. Your code helped me to starting with controlfx auto completion combobox. I have expended many time for auto completion combox. Finally I got the solution.

  4. Kristian Kongsted

    Hi, is this someting you are already looking into? How is the procedure if I would like to fix it myself and do a PR? I am sure you have a document I should read somewhere :). I guess I can just clone the repo and do a PR, always rebasing and single commits?

  5. Klaus Rheinwald

    Also, when you select an entry from the dropdown list, the text field is not simply populated with the entry and the dropdown list closed, but rather the selected entry is used to autocomplete the list, even when it is the only match. In both attached images, the entry in the text field was selected from the list, not typed in.

    2017-10-22 12_01_30.png2017-10-22 12_01_17-.png

  6. Klaus Rheinwald

    Aaargh. I misread the initial post. What I described is exactly what you described, @Peter Trefonas . What I thouhgt you described is that a second (the original?) dropdown list shows when you click the combobox box down arrow while the autocompletion list is showing.

  7. Peter Trefonas reporter

    @Klaus Rheinwald

    Makes sense. I ended up implementing my own one that was not based on this at all for my project. I did not make a general one however, just one specific for my implementation.

    It's been a while but here was the code I used. `

    import java.time.LocalDate;
    import java.util.Collections;
    
    import java.util.Map;
    import java.util.HashMap;
    import java.util.List;
    import java.util.ArrayList;
    
    import javafx.scene.input.*;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    import javafx.fxml.Initializable;
    import javafx.event.*;
    import javafx.collections.*;
    
    import javafx.fxml.FXML;
    import javafx.scene.control.*;
    import javafx.scene.paint.*;
    import javafx.scene.control.TableColumn.CellEditEvent;
    import javafx.beans.property.*;
    import javafx.scene.control.cell.*;
    
    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();
        }
    
        @Override
        public void handle(KeyEvent event) {
          if (event.getCode() == KeyCode.DOWN){
            if(!comboBox.isShowing())comboBox.show();
            return;
          }
    
            if (event.getCode().isModifierKey()||event.getCode().isNavigationKey()||event.getCode().isFunctionKey()){
              return;
            }
    
            comboBox.hide();
    
            if (event.getCode() == KeyCode.ENTER||event.getCode() == KeyCode.TAB){
                return;
            }
            if (event.getCode() ==KeyCode.ESCAPE||event.getCode() ==KeyCode.DELETE){
              comboBox.getEditor().setText("");
              comboBox.setValue(null);
              comboBox.setItems(data);
              return;
            }
            if(event.getCode() == KeyCode.BACK_SPACE) {
                moveCaretToPos = true;
                caretPos = comboBox.getEditor().getCaretPosition();
            }
    
    
    
            ObservableList<T> list = FXCollections.observableArrayList();
            if(data!=null){
              for (int i=0; i<data.size(); i++) {
                if(data.get(i).toString().toLowerCase().contains(
                                                                 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;
        }
    
    }
    
    
    
    
    And in the main code:
    
    
      public static void setItems(ComboBox<String> cb,ArrayList<String> items){
        String initialValue = cb.getValue();
        //possibly unnecessary?
        cb.setItems(null);
        cb.getEditor().setText("");
        //meat of the method
        if(items!=null&&items.size()>0)cb.setItems(FXCollections.observableList(items));
        cb.setOnKeyReleased(new AutoCompleteComboBoxListener<String>(cb));
        //Focus the combobox's change listeners on the correct values
        cb.setValue(".");
        cb.setValue(initialValue);
    
    
      }
    

    `

  8. Klaus Rheinwald

    The problem with the current implementation seems to be that the AutoCompletion on the TextField knows nothing about the surrounding ComboBox. Not sure whether this can be solved wihtout a dedicated AutoCompletion for ComboBoxes.

    I worked around the problem by using a (Custom-)TextField instead of a ComboBox. Only caveat is that the AutoCompletion list can not be shown (e.g. on key-down or click on the TextField Decoration) due to AutoCompletion#showPopup having protected access.

  9. Log in to comment