我的 JavaFX 项目有问题。我有一个可与我的
TableView
配合使用的搜索栏。我创建了一个“总计”TextField
,它应该显示表中所有记录的总数。但我的意思是所有记录,我的意思是所有记录,例如在使用搜索栏过滤记录之后。目前,当我使用搜索栏过滤表记录时,“总计”TextField
仍然显示数据库中此列中所有记录的总值,而不是当前在TableView
中的所有记录。你能看一下并帮我找出我应该做什么才能让它发挥作用吗?
这是我的代码:
private void searchData() {
FilteredList<Data> filteredData = new FilteredList<>(getDataList(), b -> true);
search.textProperty().addListener((observable, oldValue, newValue) -> filteredData.setPredicate(Data -> {
if(newValue.isEmpty() || newValue.isBlank()) {
return true;
}
String lowerCase = newValue.toLowerCase();
if(Data.getName().toLowerCase().contains(lowerCase)) {
return true;
}
else if(Data.getCategory().toLowerCase().contains(lowerCase)) {
return true;
}
else if(String.valueOf(Data.getPrice()).toLowerCase().contains(lowerCase)) {
return true;
}
else
return String.valueOf(Data.getDate()).toLowerCase().contains(lowerCase);
}));
SortedList<Data> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(table.comparatorProperty());
table.setItems(sortedData);
total();
}
private void total() {
int totalAmount = 0;
totalAmount = table.getItems()
.stream()
.map((item) -> item.getPrice())
.reduce(totalAmount, (accumulation, _item) -> accumulation + _item);
total.setText(String.valueOf(totalAmount));
}
编辑1:
private void searchData() {
FilteredList<Data> filteredData = new FilteredList<>(getDataList(), b -> true);
search.textProperty().addListener((observable, oldValue, newValue) -> filteredData.setPredicate(Data -> {
if(newValue.isEmpty() || newValue.isBlank()) {
total();
return true;
}
String lowerCase = newValue.toLowerCase();
if(Data.getName().toLowerCase().contains(lowerCase)) {
total();
return true;
}
else if(Data.getCategory().toLowerCase().contains(lowerCase)) {
total();
return true;
}
else if(String.valueOf(Data.getPrice()).toLowerCase().contains(lowerCase)) {
total();
return true;
}
else if(String.valueOf(Data.getDate()).toLowerCase().contains(lowerCase)) {
total();
return true;
}
else return false;
}));
SortedList<Data> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(table.comparatorProperty());
table.setItems(sortedData);
}
在第一次尝试编写代码时,当您使用搜索字段的文本属性注册侦听器时,只需调用
total()
一次。 total()
方法永远不会被再次调用,因此当表中的项目发生变化时,总数不会更新。
在第二次尝试中,您在实际谓词内调用
total()
,用于确定元素是否应包含在过滤列表中。你实际上不知道这些谓词何时会被执行:这是 FilteredList
的内部实现细节。谓词应该简单地返回 true
或 false
,具体取决于元素是否应包含在列表中;这些方法有副作用是没有意义的。
每次数据变化时都需要重新计算总数。执行此操作的一种方法(假设您没有在其他地方更改数据)是简单地在侦听器中调用
total()
来更改搜索字段的文本属性:
private void searchData() {
FilteredList<Data> filteredData = new FilteredList<>(getDataList(), b -> true);
search.textProperty().addListener((observable, oldValue, newValue) -> {
filteredData.setPredicate(Data -> {
if(newValue.isEmpty() || newValue.isBlank()) {
return true;
}
String lowerCase = newValue.toLowerCase();
if(Data.getName().toLowerCase().contains(lowerCase)) {
return true;
}
else if(Data.getCategory().toLowerCase().contains(lowerCase)) {
return true;
}
else if(String.valueOf(Data.getPrice()).toLowerCase().contains(lowerCase)) {
return true;
}
else
return String.valueOf(Data.getDate()).toLowerCase().contains(lowerCase);
});
total();
});
SortedList<Data> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(table.comparatorProperty());
table.setItems(sortedData);
total();
}
您不会在其他地方更改数据的假设可能太大了。 (例如,即使您现在不这样做,您也可能希望添加功能以将新数据添加到表中,在这种情况下,当您添加新数据时,总数不会更新。)更好的方法是注册侦听器或与列表的绑定。 (这假设您没有在代码中的其他任何地方调用
table.setItems()
,但在大多数情况下这是一个合理的假设。)
你可以做
private void searchData() {
FilteredList<Data> filteredData = new FilteredList<>(getDataList(), b -> true);
search.textProperty().addListener((observable, oldValue, newValue) -> {
filteredData.setPredicate(Data -> {
if(newValue.isEmpty() || newValue.isBlank()) {
return true;
}
String lowerCase = newValue.toLowerCase();
if(Data.getName().toLowerCase().contains(lowerCase)) {
return true;
}
else if(Data.getCategory().toLowerCase().contains(lowerCase)) {
return true;
}
else if(String.valueOf(Data.getPrice()).toLowerCase().contains(lowerCase)) {
return true;
}
else
return String.valueOf(Data.getDate()).toLowerCase().contains(lowerCase);
});
});
SortedList<Data> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(table.comparatorProperty());
table.setItems(sortedData);
sortedData.addListener((ListChangeListener.Change<? extends Data> c) -> total());
total();
}
或带有装订:
private void searchData() {
FilteredList<Data> filteredData = new FilteredList<>(getDataList(), b -> true);
search.textProperty().addListener((observable, oldValue, newValue) -> {
filteredData.setPredicate(Data -> {
if(newValue.isEmpty() || newValue.isBlank()) {
return true;
}
String lowerCase = newValue.toLowerCase();
if(Data.getName().toLowerCase().contains(lowerCase)) {
return true;
}
else if(Data.getCategory().toLowerCase().contains(lowerCase)) {
return true;
}
else if(String.valueOf(Data.getPrice()).toLowerCase().contains(lowerCase)) {
return true;
}
else
return String.valueOf(Data.getDate()).toLowerCase().contains(lowerCase);
});
});
SortedList<Data> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(table.comparatorProperty());
table.setItems(sortedData);
total.textProperty().bind(Bindings.createStringBinding(
this::total,
sortedData
));
}
绑定版本需要对
total()
方法进行小修改:
private String total() {
int totalAmount = table.getItems()
.stream()
//.map((item) -> item.getPrice())
//.reduce(totalAmount, (accumulation, _item) -> accumulation + _item);
// simplified code:
.collect(Collectors.summingDouble(Data::getPrice));
return String.valueOf(totalAmount);
}