[英]JavaFX deleting from TableView
我正在开发 JavaFX 应用程序,并使用 TableView 作为 GUI 的一部分,如下所示:
public TableView<Meal> meals;
并为其分配了一个按钮,该按钮应该删除选定的元素。 为此,我使用了一个不断给我 NoSuchElementException 的函数
public void deleteMealButtonClicked()
{
ObservableList<Meal> mealsSelected = meals.getSelectionModel().getSelectedItems();
ObservableList<Meal> allMeals = meals.getItems();
mealsSelected.forEach(allMeals::remove);
}
我通过调试发现问题出在方法的最后一行。
研究了半天,偶然发现一段代码解决了这个问题。 这是具有有效代码的方法:
public void deleteMealButtonClicked()
{
ObservableList<Meal> mealsSelected = meals.getSelectionModel().getSelectedItems();
ObservableList<Meal> allMeals = meals.getItems();
if (mealsSelected != null) {
ArrayList<Meal> rows = new ArrayList<>(mealsSelected);
rows.forEach(row -> meals.getItems().remove(row));
}
}
我的问题是,为什么第二种方法有效而不是第一种方法? 除了将所选行添加到第二种方法的 ArrayList 之外,它们从根本上不是一回事吗?
先感谢您。
TableView
的选择模型必须观察items
属性中的ObservableList
才能正确反映表格的状态。 换句话说,如果一个元素从items
删除,它也必须从选择模型的选定项目中删除。
这导致您在迭代它以从meals
列表中删除包含的元素时间接修改selectedMeals
列表。 在很多java.util
集合中,迭代器是快速失败的,这将导致ConcurrentModificationException
; 我猜选择模型不是快速失败的,因此您只会看到不确定的行为(以NullPointerException
的形式)。
第二个选项有效,因为您首先制作selectedMeals
的副本,然后迭代该副本。
您在评论中要求不创建副本的方法; 不幸的是,我想不出一个。 但是,您可以使用removeAll
稍微简化您的代码。
ObservableList<Meal> selected = ...;
// List.copyOf is a Java 10 method (and doesn't accept null elements)
table.getItems().removeAll(List.copyOf(selected));
// Pre Java 10 you can use toArray since ObservableList overloads removeAll
// with a version that takes a varargs parameter
table.getItems().removeAll(selected.toArray(new Meal[0]));
// or use the copy constructor of many collection classes
table.getItems().removeAll(new ArrayList<>(selected));
// In Java 11, toArray can be replaced with
table.getItems().removeAll(selected.toArray(Meal[]::new));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.