Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javafx combobox with custom object displays object address though custom cell factory is used

I have a combobox which shows list of User objects. I have coded a custom cell factory for the combobox:

@FXML ComboBox<User> cmbUserIds;
cmbUserIds.setCellFactory(new Callback<ListView<User>,ListCell<User>>(){
                @Override
                public ListCell<User> call(ListView<User> l){
                    return new ListCell<User>(){
                        @Override
                        protected void updateItem(Useritem, boolean empty) {
                            super.updateItem(item, empty);
                            if (item == null || empty) {
                                setGraphic(null);
                            } else {
                                setText(item.getId()+"    "+item.getName());
                            }
                        }
                    } ;
                }
            });

ListView is showing a string(id+name), but when I select an item from listview, Combobox is showing toString() method return value i.e address of object. I can't override toString() method, because the User domain object should be same as the one at server. How to display id in combobox? Please suggest

EDIT1

I tried below code. Now combo box shows id when I select a value from the listview.

cmbUserIds.setConverter(new StringConverter<User>() {
              @Override
              public String toString(User user) {
                if (user== null){
                  return null;
                } else {
                  return user.getId();
                }
              }

            @Override
            public User fromString(String id) {
                return null;
            }
        });

The selected value in combo box is cleared when control focus is lost. How to fix this?

EDIT2:

@FXML AnchorPane root;
@FXML ComboBox<UserDTO> cmbUsers;
List<UserDTO> users;
public class GateInController implements Initializable {
@Override   
public void initialize(URL location, ResourceBundle resources) {
        users = UserService.getListOfUsers();
        cmbUsers.setItems(FXCollections.observableList(users));
        cmbUsers.getSelectionModel().selectFirst();
        // list of values showed in combo box drop down
        cmbUsers.setCellFactory(new Callback<ListView<UserDTO>,ListCell<UserDTO>>(){
            @Override
            public ListCell<UserDTO> call(ListView<UserDTO> l){
                return new ListCell<UserDTO>(){
                    @Override
                    protected void updateItem(UserDTO item, boolean empty) {
                        super.updateItem(item, empty);
                        if (item == null || empty) {
                            setGraphic(null);
                        } else {
                            setText(item.getUserId()+"    "+item.getUserNm());
                        }
                    }
                } ;
            }
        });
        //selected value showed in combo box
        cmbUsers.setConverter(new StringConverter<UserDTO>() {
              @Override
              public String toString(UserDTO user) {
                if (user == null){
                  return null;
                } else {
                  return user.getUserId();
                }
              }

            @Override
            public UserDTO fromString(String userId) {
                return null;
            }
        });
    }
}
like image 613
developer Avatar asked Nov 29 '13 10:11

developer


2 Answers

Just create and set a CallBack like follows:

@FXML ComboBox<User> cmbUserIds;

Callback<ListView<User>, ListCell<User>> cellFactory = new Callback<ListView<User>, ListCell<User>>() {

    @Override
    public ListCell<User> call(ListView<User> l) {
        return new ListCell<User>() {

            @Override
            protected void updateItem(User item, boolean empty) {
                super.updateItem(item, empty);
                if (item == null || empty) {
                    setGraphic(null);
                } else {
                    setText(item.getId() + "    " + item.getName());
                }
            }
        } ;
    }
}

// Just set the button cell here:
cmbUserIds.setButtonCell(cellFactory.call(null));
cmbUserIds.setCellFactory(cellFactory);
like image 50
Chris River Avatar answered Oct 19 '22 13:10

Chris River


You need to provide a functional fromString() Method within the Converter!

I had the same problem as you have and as I implemented the fromString() with working code, the ComboBox behaves as expected.

This class provides a few of my objects, for dev-test purposes:

public class DevCatProvider {

    public static final CategoryObject c1;
    public static final CategoryObject c2;
    public static final CategoryObject c3;

    static {
        // Init objects
    }

    public static CategoryObject getCatForName(final String name) {
        switch (name) {
            case "Kategorie 1":
                return c1;

            case "Cat 2":
                return c2;

            case "Steuer":
                return c3;

            default:
                return c1;
        }
    }
}

The converter object:

public class CategoryChooserConverter<T> extends StringConverter<CategoryObject> {

    @Override
    public CategoryObject fromString(final String catName) {
        //This is the important code!
        return Dev_CatProvider.getCatForName(catName);
    }

    @Override
    public String toString(final CategoryObject categoryObject) {
        if (categoryObject == null) {
            return null;
        }
        return categoryObject.getName();
    }
}
like image 9
Korashen Avatar answered Oct 19 '22 12:10

Korashen