我使用JavaFX创建了一个简单的待办事项列表应用程序。在做了一些研究之后,我想出了如何使ListView可编辑(这样双击单元格就可以让你更改里面的文本)。到目前为止一切正常,但我对setOnEditCommit方法在我的代码中扮演什么角色感到困惑。这是我的整个初始化方法,setOnEditCommit位于底部。
public void initialize()
{
listContextMenu = new ContextMenu();
MenuItem deleteMenuItem = new MenuItem("Delete");
deleteMenuItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
TodoItem item = todoListView.getSelectionModel().getSelectedItem();
deleteItem(item);
}
});
listContextMenu.getItems().addAll(deleteMenuItem);
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();
itemDetailsTextArea.setText(item.getDetails());
DateTimeFormatter df = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
deadlineLabel.setText(item.getDeadline().format(df));
}
}
});
wantAllItems = new Predicate<TodoItem>() {
@Override
public boolean test(TodoItem todoItem) {
return true;
}
};
wantTodaysItems = new Predicate<TodoItem>() {
@Override
public boolean test(TodoItem todoItem) {
return todoItem.getDeadline().equals(LocalDate.now());
}
};
filteredList = new FilteredList<TodoItem>(TodoData.getInstance().getTodoitems(), wantAllItems);
SortedList<TodoItem> sortedList = new SortedList<TodoItem>(filteredList,
new Comparator<TodoItem>() {
@Override
public int compare(TodoItem o1, TodoItem o2) {
return o1.getDeadline().compareTo(o2.getDeadline());
}
});
//todoListView.setItems(TodoData.getInstance().getTodoitems());
todoListView.setItems(sortedList);
todoListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
todoListView.getSelectionModel().selectFirst();
todoListView.setEditable(true);
todoListView.setCellFactory(new Callback<ListView<TodoItem>, ListCell<TodoItem>>() {
@Override
public ListCell<TodoItem> call(ListView<TodoItem> lv) {
TextFieldListCell<TodoItem> cell = new TextFieldListCell<TodoItem>(){
@Override
public void updateItem(TodoItem item, boolean empty) {
super.updateItem(item, empty);
if(empty){
setText(null);
} else {
setText(item.getShortDescription());
if(item.getDeadline().isBefore(LocalDate.now().plusDays(1)))
setTextFill(Color.RED);
else if(item.getDeadline().equals(LocalDate.now().plusDays(1)))
setTextFill(Color.BROWN);
}
}
};
cell.emptyProperty().addListener(
(obs, wasEmpty, isNowEmpty) ->
{
if(isNowEmpty)
cell.setContextMenu(null);
else
cell.setContextMenu(listContextMenu);
}
);
cell.setConverter(new StringConverter<TodoItem>() {
@Override
public String toString(TodoItem object) {
return object.toString();
}
@Override
public TodoItem fromString(String string) {
cell.getItem().setShortDescription(string);
return cell.getItem();
}
});
return cell;
}
});
// this is the method where the source of the exception is being reported
todoListView.setOnEditCommit(new EventHandler<ListView.EditEvent<TodoItem>>() {
@Override
public void handle(ListView.EditEvent<TodoItem> e) {
}
});
}
现在我很困惑,因为注释掉setOnEditCommit方法会导致异常。显然我需要它。但是,重写的句柄函数里面什么也没做,里面没有代码行。那么为什么有必要保留这个以及它做什么呢?这叫什么时候?
请记住我的待办事项清单功能就好了。提交并保存编辑,以便您在下次运行时可以看到它们。我觉得我对某些事情产生了极大的误解。
答案 0 :(得分:0)
提交并修改TextFieldListCell
这样的作品:
如果设置了onEditCommit
处理程序,则ListView
会假定此处理程序用于处理编辑。
如果未设置onEditCommit
处理程序,则使用转换器将TextField
内容转换为项目的结果将设置为单元格中项目的索引。
由于您使用SortedList
ListView
调用set
会产生异常(该列表只是一个不同ObservableList
的视图,无法直接修改)。设置onEditCommit
处理程序会阻止ListView
调用SortedList.set
,从而防止出错。
答案 1 :(得分:0)
默认情况下,ListView编辑提交处理程序为非null,其默认处理程序尝试覆盖当前正在编辑的行中的项的属性值。 ...非常重要的是要注意,如果您使用自己的EventHandler调用
setOnEditCommit(javafx.event.EventHandler)
,那么您将删除默认处理程序。
当您提交修改时,TextFieldListCell
会触发ListView.EditEvent
事件,其newValue
是通过将文本字段的文本传递给转换器的fromString()
方法而创建的值。
默认的onEditCommit()
处理程序获取该值并将其设置在列表中。即它做了一些事情
event.getSource().getItems().set(event.getIndex(), event.getNewValue());
由于您使用不可修改的列表(SortedList
)作为ListView
的项目列表,因此尝试在其中设置值会引发{{1} }。
通过显式设置UnsupportedOperationException
处理程序,删除默认处理程序,因此异常消失。由于您的onEditCommit
实际上已经完成了更新数据的工作(纯粹主义者可能认为这违反了关注点的分离),因此您实际上不需要在此处理程序中执行任何操作。
如果您的转换器没有为您修改该项目(例如,通过返回新的converter
):
TodoItem
然后你需要你的处理程序更新支持列表,你可以使用
cell.setConverter(new StringConverter<TodoItem>() {
@Override
public String toString(TodoItem object) {
// shouldn't this return the property that you're editing?
return object.getShortDescription();
}
@Override
public TodoItem fromString(String string) {
TodoItem currentItem = cell.getItem();
TodoItem editedItem = new TodoItem();
editedItem.setShortDescription(string);
editedItem.setDeadline(currentItem.getDeadline());
// etc...
return editedItem ;
}
});
(假设todoListView.setOnEditCommit(e -> {
int indexInSortedList = e.getIndex();
int indexInFilteredList = sortedList.getSourceIndex(indexInSortedList);
int indexInOriginalList = filteredList.getSourceIndex(indexInFilteredList);
TodoData.getInstance().getTodoitems().set(indexInOriginalList, e.getNewValue());
});
返回的列表是可修改的)。