Combobox 带有自定义对象的Javafx组合框显示对象地址,尽管使用了自定义单元格工厂

Combobox 带有自定义对象的Javafx组合框显示对象地址,尽管使用了自定义单元格工厂,combobox,javafx-2,Combobox,Javafx 2,我有一个组合框,显示User对象的列表。我为组合框编写了一个自定义单元格工厂: @FXML ComboBox<User> cmbUserIds; cmbUserIds.setCellFactory(new Callback<ListView<User>,ListCell<User>>(){ @Override public ListCell<User> call(ListV

我有一个组合框,显示
User
对象的列表。我为组合框编写了一个自定义单元格工厂:

@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());
                            }
                        }
                    } ;
                }
            });
@FXML组合框cmbuserid;
cmbUserIds.setCellFactory(新回调(){
@凌驾
公共ListCell调用(ListView l){
返回新的ListCell(){
@凌驾
受保护的void updateItem(Useritem,布尔值为空){
super.updateItem(项,空);
如果(项==null | |空){
设置图形(空);
}否则{
setText(item.getId()+“”+item.getName());
}
}
} ;
}
});
ListView显示一个字符串(id+名称),但当我从ListView中选择一个项目时,Combobox显示toString()方法返回值,即对象的地址。 我无法重写toString()方法,因为用户域对象应该与服务器上的对象相同。 如何在组合框中显示id?请建议

编辑1

我尝试了下面的代码。现在,当我从listview中选择一个值时,组合框显示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;
            }
        });
cmbUserIds.setConverter(新的StringConverter(){
@凌驾
公共字符串toString(用户){
if(user==null){
返回null;
}否则{
返回user.getId();
}
}
@凌驾
公共用户fromString(字符串id){
返回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;
            }
        });
    }
}
@FXML锚烷根;
@FXML组合框用户;
列出用户名单;
公共类网关InControl实现可初始化{
@凌驾
公共void初始化(URL位置、ResourceBundle资源){
users=UserService.getListOfUsers();
cmbUsers.setItems(FXCollections.observableList(users));
cmbUsers.getSelectionModel().selectFirst();
//组合框下拉列表中显示的值列表
cmbUsers.setCellFactory(新回调(){
@凌驾
公共ListCell调用(ListView l){
返回新的ListCell(){
@凌驾
受保护的void updateItem(UserDTO项,布尔值为空){
super.updateItem(项,空);
如果(项==null | |空){
设置图形(空);
}否则{
setText(item.getUserId()+“”+item.getUserNm());
}
}
} ;
}
});
//选择值显示在组合框中
cmbUsers.setConverter(新的StringConverter(){
@凌驾
公共字符串到字符串(用户到用户){
if(user==null){
返回null;
}否则{
返回user.getUserId();
}
}
@凌驾
public UserDTO fromString(String userId){
返回null;
}
});
}
}

您需要在转换器内提供一个功能性的
fromString()
方法

我遇到了与您相同的问题,当我使用工作代码实现
fromString()
时,组合框的行为与预期的一样

此类提供了一些my对象,用于开发人员测试:

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();
    }
}
公共类CategoryChooserConverter扩展StringConverter{
@凌驾
public CategoryObject fromString(最终字符串catName){
//这是重要的代码!
返回Dev_CatProvider.getCatForName(catName);
}
@凌驾
公共字符串到字符串(最终类别对象类别对象){
if(categoryObject==null){
返回null;
}
返回categoryObject.getName();
}
}

只需创建并设置一个
回调
,如下所示:

@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);
@FXML组合框cmbuserid;
Callback cellFactory=new Callback(){
@凌驾
公共ListCell调用(ListView l){
返回新的ListCell(){
@凌驾
受保护的void updateItem(用户项,布尔值为空){
super.updateItem(项,空);
如果(项==null | |空){
设置图形(空);
}否则{
setText(item.getId()+“”+item.getName());
}
}
} ;
}
}
//只需在此处设置按钮单元格:
cmbUserIds.setButtonCell(cellFactory.call(null));
cmbUserId.setCellFactory(cellFactory);

转换器属性Javadoc似乎不合适。我刚刚提出了一个问题:我讨厌他们这样做,不得不用字符串比较f。为什么他们不在其他东西上添加一个类似的
comboBox.setText(User::getName)
?对setButtonCell()的调用是如何工作的?它看起来像是立即用null调用callFactory,然后将返回传递给setButtonCell(),但这对它的工作方式没有意义,因为它非常有用。你能解释一下幕后发生了什么吗?@simpleuser如果你看上面的代码,call的返回值是一个ListCell。因此,这里要做的是将自定义ListCell(它覆盖updateItem方法)设置为button单元格。