Search code examples
comboboxjavafx-2javafxjavafx-8

JavaFX Editable ComboBox : Showing toString on item selection


I have a ComboBox<Person>, of type Person, in which I have added few object of Person class.

I have used setCellFactory(Callback) method to show Person name in ComboBox drop down

combobox.setCellFactory(
    new Callback<ListView<Person >, ListCell<Person >>() {
        @Override
        public ListCell<Person > call(ListView<Person > p) {
            ListCell cell = new ListCell<Person >() {
                @Override
                protected void updateItem(Person item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty) {
                        setText("");
                    } else {
                        setText(item.getName());
                    }
                }
            };
            return cell;
        }
    });

And, setButtonCell(ListCell) method to show name in combobox on selection.

combobox.setButtonCell(
    new ListCell<Object>() {
        @Override
        protected void updateItem(Person t, boolean bln) {
            super.updateItem(t, bln); 
            if (bln) {
                setText("");
            } else {
                setText(t.getName());
            }
        }
    });

This works perfectly good with normal case but when I use editable combobox then this fails.

When I write , combobox.setEditable(true); then on item selection the text field (editor) of combobox shows toString() method of Person class.

Normal Case : Normal Case

Editable Case : Editable Case

Is there any solution for this?

I have a model class:

public class Person {
    String name;
    int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" + "name=" + name + ", age=" + age + '}';
    }
}

Solution

  • Here is an answer to my own question which I found best after many efforts and corrections.

    mainComboBox.setButtonCell(
        new ListCell<Object>() {
            @Override
            protected void updateItem(Object t, boolean bln) {
                super.updateItem(t, bln);
                if (bln) {
                    setText("");
                } else {
                    setText(getStringField(t));
                }
            }
        });
    
    mainComboBox.setConverter(
        new StringConverter() {
            private Map<String, Object> map = new HashMap<>();
    
            @Override
            public String toString(Object t) {
                if (t != null) {
                    String str = getStringField(t);
                    map.put(str, t);
                    return str;
                } else {
                    return "";
                }
            }
    
            @Override
            public Object fromString(String string) {
                if (validate && !map.containsKey(string)) {
                    mainComboBox.setValue(null);
                    mainComboBox.getEditor().clear();
                    return null;
                }
                return map.get(string);
            }
        });
    
    mainComboBox.setCellFactory(
        new Callback<ListView<Object>, ListCell<Object>>() {
            @Override
            public ListCell<Object> call(ListView<Object> p) {
                ListCell cell = new ListCell<Object>() {
                    @Override
                    protected void updateItem(Object item, boolean empty) {
                        super.updateItem(item, empty);
                        if (empty) {
                            setText("");
                        } else {
                            setText(getStringField(item));
                        }
                    }
                };return cell;
            }
        });
    

    And with required function of getStringField(Object),

    public String getStringField(Object o) {
        return ((Pesron) o).getName();
    }