Javafx combobox с настраиваемым объектом отображает адрес объекта, хотя используется специальная ячейка factory
У меня есть combobox, который показывает список объектов User
. Я закодировал пользовательскую ячейку factory для 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 показывает строку (id + name), но когда я выбираю элемент из списка, Combobox показывает значение метода toString() для возвращаемого значения i.e объекта.
Я не могу переопределить метод toString(), потому что объект домена пользователя должен быть таким же, как тот, что на сервере.
Как отображать идентификатор в combobox? Пожалуйста, предложите
EDIT1
Я попробовал под кодом. Теперь поле со списком показывает id, когда я выбираю значение из списка.
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;
}
});
Выбранное значение в поле со списком очищается, когда фокус управления теряется. Как это исправить?
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;
}
});
}
}
Ответы
Ответ 1
Просто создайте и установите CallBack
следующим образом:
@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);
Ответ 2
Вам необходимо предоставить функциональный fromString()
метод в конвертере!
У меня была такая же проблема, как у вас, и когда я реализовал fromString()
с рабочим кодом, ComboBox ведет себя как и ожидалось.
Этот класс предоставляет несколько моих объектов для целей dev-test:
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;
}
}
}
Объект конвертера:
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();
}
}