为何在ListView监听器外调用getSelectedItem()返回null?是否需在监听器内调用?
问题
现有如下JavaFX代码运行正常:
TodoItem类
public class TodoItem { private String description; private String details; private LocalDate deadline; public TodoItem(String description, String details, LocalDate deadline) { this.description = description; this.details = details; this.deadline = deadline; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getDetails() { return details; } public void setDetails(String details) { this.details = details; } public LocalDate getDeadline() { return deadline; } }
Controller类
public class Controller { @FXML private ListView<TodoItem> todoListView; @FXML private TextArea todoDetails; @FXML private Label todoDeadLine; private List<TodoItem> todoItems; public void initialize() { todoListView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TodoItem>() { @Override public void changed(ObservableValue<? extends TodoItem> observable, TodoItem oldValue, TodoItem newValue) { if(newValue != null) { TodoItem item = todoListView.getSelectionModel().getSelectedItem(); todoDetails.setText(item.getDetails()); DateTimeFormatter df = DateTimeFormatter.ofPattern("MMMM d, yyyy"); // "d M yy"); todoDeadLine.setText(df.format(item.getDeadline())); } } }); } }
但当我将代码TodoItem item = todoListView.getSelectionModel().getSelectedItem();移到ChangeListener监听器外部(注释掉原监听器代码)时,获取到的是null值。请问是否必须在监听器内部调用该代码才能获取到选中项数据?
回答
不是必须在监听器内部调用,但你拿到null的核心原因是调用时机不对:
initialize()方法执行时,JavaFX界面刚完成初始化,此时ListView还没有任何选中项(用户还没做选择操作),直接调用getSelectedItem()自然返回null。- 监听器的作用是监听选中项的变化事件,只有当用户手动选中某个项,或者通过代码主动设置选中项时,监听器的
changed()方法才会触发,这时调用getSelectedItem()才能拿到有效的选中对象。
如果想在监听器外部获取选中项,只要确保调用代码的时机是在选中项已经存在之后即可,比如:
- 在用户点击按钮的事件处理方法中调用
- 在代码主动设置了选中项之后调用
另外补充个小优化:监听器的changed()方法里已经提供了newValue参数,它就是当前选中的项,完全没必要再调用getSelectedItem(),直接用newValue就能简化代码:
@Override public void changed(ObservableValue<? extends TodoItem> observable, TodoItem oldValue, TodoItem newValue) { if(newValue != null) { todoDetails.setText(newValue.getDetails()); DateTimeFormatter df = DateTimeFormatter.ofPattern("MMMM d, yyyy"); todoDeadLine.setText(df.format(newValue.getDeadline())); } }
内容的提问来源于stack exchange,提问作者MaTa
相关产品推荐
相关产品推荐

