如何通过过滤计算 Vaadin 8 网格页脚中的总数
How to calculate the total in a Vaadin 8 grid footer with filtering
我知道我必须使用 grid.getDataProvider()
来获取 ListDataProvider
(假设我向 grid.setItems()
发送了一个 List
)。在其他计算页脚总计我做的:
Collection myItems = ((ListDataProvider)grid.getDataProvider()).getItems();
for(MyItem myItem : myItems)
total += myItem.getValue();
footer.getCell(footerCell).setText(format(total));
但是如果我添加页脚,这会失败,因为它会计算我网格中的所有项目。例如,如果我添加:
((ListDataProvider)grid.getDataProvider()).addFilter(myFilter);
顶部的代码失败,因为页脚不是过滤后的总计,而是完整的网格总计。
grid.getDataCommunicator().fetchItemsWithRange(...);
但是这是一个受保护的方法。假设我创建自己的子类,我什至不明白该方法是如何工作的。
但即便如此,这似乎还是过于复杂,而且应该很简单,尤其是如果能够在网格中添加过滤功能。
因此我的大问题是,如果我过滤网格,如何计算 Vaadin 8 网格中的页脚总数?
要重新计算总数,您可以使用 DataProviderListener which is triggered when the filter changes. In its implementation you can fetch the items from DataProvider with a Query,因为获取方法也会考虑您定义的过滤器。
下面的例子主要基于Vaadin grid sampler,其想法是显示每月报价列表及其总计。过滤器将允许您查看从某个月开始的数据(这很愚蠢,但可以帮助您入门):
import com.vaadin.data.provider.ListDataProvider;
import com.vaadin.data.provider.Query;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Grid;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.components.grid.FooterRow;
import com.vaadin.ui.components.grid.HeaderRow;
import com.vaadin.ui.themes.ValoTheme;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class FilteredGrid extends VerticalLayout {
public FilteredGrid() {
// list data provider with some random data
Random random = new Random();
List<Quote> quotes = IntStream.range(1, 11).mapToObj(month -> new Quote(month, random.nextInt(10))).collect(Collectors.toList());
ListDataProvider<Quote> provider = new ListDataProvider<>(quotes);
// month number filter combo
ComboBox<Integer> monthFilterCombo = new ComboBox<>("Starting with", IntStream.range(1, 10).boxed().collect(Collectors.toList()));
monthFilterCombo.setEmptySelectionCaption("All");
monthFilterCombo.addStyleName(ValoTheme.COMBOBOX_SMALL);
monthFilterCombo.addValueChangeListener(event -> {
if (event.getValue() == null) {
provider.clearFilters();
} else {
provider.setFilter(quote -> quote.getMonth() > event.getValue());
}
});
// grid setup
Grid<Quote> grid = new Grid<>(Quote.class);
grid.setDataProvider(provider);
// header and footer
HeaderRow header = grid.appendHeaderRow();
header.getCell("month").setComponent(monthFilterCombo);
FooterRow footer = grid.prependFooterRow();
footer.getCell("month").setHtml("<b>Total:</b>");
provider.addDataProviderListener(event -> footer.getCell("value").setHtml(calculateTotal(provider)));
// add grid to UI
setSizeFull();
grid.setSizeFull();
addComponent(grid);
// trigger initial calculation
provider.refreshAll();
}
// calculate the total of the filtered data
private String calculateTotal(ListDataProvider<Quote> provider) {
return "<b>" + String.valueOf(provider.fetch(new Query<>()).mapToInt(Quote::getValue).sum()) + "</b>";
}
// basic bean for easy binding
public class Quote {
private int month;
private int value;
public Quote(int month, int value) {
this.month = month;
this.value = value;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
}
结果:
我知道我必须使用 grid.getDataProvider()
来获取 ListDataProvider
(假设我向 grid.setItems()
发送了一个 List
)。在其他计算页脚总计我做的:
Collection myItems = ((ListDataProvider)grid.getDataProvider()).getItems();
for(MyItem myItem : myItems)
total += myItem.getValue();
footer.getCell(footerCell).setText(format(total));
但是如果我添加页脚,这会失败,因为它会计算我网格中的所有项目。例如,如果我添加:
((ListDataProvider)grid.getDataProvider()).addFilter(myFilter);
顶部的代码失败,因为页脚不是过滤后的总计,而是完整的网格总计。
grid.getDataCommunicator().fetchItemsWithRange(...);
但是这是一个受保护的方法。假设我创建自己的子类,我什至不明白该方法是如何工作的。
但即便如此,这似乎还是过于复杂,而且应该很简单,尤其是如果能够在网格中添加过滤功能。
因此我的大问题是,如果我过滤网格,如何计算 Vaadin 8 网格中的页脚总数?
要重新计算总数,您可以使用 DataProviderListener which is triggered when the filter changes. In its implementation you can fetch the items from DataProvider with a Query,因为获取方法也会考虑您定义的过滤器。
下面的例子主要基于Vaadin grid sampler,其想法是显示每月报价列表及其总计。过滤器将允许您查看从某个月开始的数据(这很愚蠢,但可以帮助您入门):
import com.vaadin.data.provider.ListDataProvider;
import com.vaadin.data.provider.Query;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Grid;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.components.grid.FooterRow;
import com.vaadin.ui.components.grid.HeaderRow;
import com.vaadin.ui.themes.ValoTheme;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class FilteredGrid extends VerticalLayout {
public FilteredGrid() {
// list data provider with some random data
Random random = new Random();
List<Quote> quotes = IntStream.range(1, 11).mapToObj(month -> new Quote(month, random.nextInt(10))).collect(Collectors.toList());
ListDataProvider<Quote> provider = new ListDataProvider<>(quotes);
// month number filter combo
ComboBox<Integer> monthFilterCombo = new ComboBox<>("Starting with", IntStream.range(1, 10).boxed().collect(Collectors.toList()));
monthFilterCombo.setEmptySelectionCaption("All");
monthFilterCombo.addStyleName(ValoTheme.COMBOBOX_SMALL);
monthFilterCombo.addValueChangeListener(event -> {
if (event.getValue() == null) {
provider.clearFilters();
} else {
provider.setFilter(quote -> quote.getMonth() > event.getValue());
}
});
// grid setup
Grid<Quote> grid = new Grid<>(Quote.class);
grid.setDataProvider(provider);
// header and footer
HeaderRow header = grid.appendHeaderRow();
header.getCell("month").setComponent(monthFilterCombo);
FooterRow footer = grid.prependFooterRow();
footer.getCell("month").setHtml("<b>Total:</b>");
provider.addDataProviderListener(event -> footer.getCell("value").setHtml(calculateTotal(provider)));
// add grid to UI
setSizeFull();
grid.setSizeFull();
addComponent(grid);
// trigger initial calculation
provider.refreshAll();
}
// calculate the total of the filtered data
private String calculateTotal(ListDataProvider<Quote> provider) {
return "<b>" + String.valueOf(provider.fetch(new Query<>()).mapToInt(Quote::getValue).sum()) + "</b>";
}
// basic bean for easy binding
public class Quote {
private int month;
private int value;
public Quote(int month, int value) {
this.month = month;
this.value = value;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
}
结果: