在 Vaadin 8.1 TreeGrid 中替换 collapseItemsRecursively 和 expandItemsRecursively
Replacement for collapseItemsRecursively and expandItemsRecursively in Vaadin 8.1 TreeGrid
Vaadin 8.1 引入了 TreeGrid
组件。它不再有 collapseItemsRecursively
和 expandItemsRecursively
方法(在现在的遗留 Tree
组件中可用)。我错过了什么或者你需要开发自己的实现吗?如果是这样,推荐的方法是什么?
来自 docs for treegrid, you can use the methods, collapse
and expand
,通过传递树状网格数据项的列表或数组来展开或折叠:
treeGrid.expand(someTreeGridItem1, someTreeGridItem2);
treeGrid.collapse(someTreeGridItem1);
同样值得注意的是,显示 prevent certain items from ever being collapsed
能力的部分
我相信您已经注意到,TreeGrid 是一个相当新的组件,目前正在开发中,从 v8 开始可用。1.alphaX(当前的稳定版本是 v8.0.6)。因此,它目前可能只有一些基本功能,其余的将在未来的某个时候推出,尽管不能保证。例如 this similar feature request for the older TreeTable component 自 2011 年以来一直处于开放状态。
无论哪种方式,即使它们可能不是最佳解决方案,您也可以使用一些解决方法来实现此行为。我 无耻地 将 vaadin-sampler for TreeGrid.
当前可用代码的略微修改版本用作基本示例
public class RecursiveExpansionTreeGrid extends VerticalLayout {
private Random random = new Random();
public RecursiveExpansionTreeGrid() {
// common setup with some dummy data
TreeGrid<Project> treeGrid = new TreeGrid<>();
treeGrid.setItems(generateProjectsForYears(2010, 2016), Project::getSubProjects);
treeGrid.addColumn(Project::getName).setCaption("Project Name").setId("name-column");
treeGrid.addColumn(Project::getHoursDone).setCaption("Hours Done");
treeGrid.addColumn(Project::getLastModified).setCaption("Last Modified");
addComponent(treeGrid);
}
// generate some dummy data to display in the tree grid
private List<Project> generateProjectsForYears(int startYear, int endYear) {
List<Project> projects = new ArrayList<>();
for (int year = startYear; year <= endYear; year++) {
Project yearProject = new Project("Year " + year);
for (int i = 1; i < 2 + random.nextInt(5); i++) {
Project customerProject = new Project("Customer Project " + i);
customerProject.setSubProjects(Arrays.asList(
new LeafProject("Implementation", random.nextInt(100), year),
new LeafProject("Planning", random.nextInt(10), year),
new LeafProject("Prototyping", random.nextInt(20), year)));
yearProject.addSubProject(customerProject);
}
projects.add(yearProject);
}
return projects;
}
// POJO for easy binding
public class Project {
private List<Project> subProjects = new ArrayList<>();
private String name;
public Project(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Project> getSubProjects() {
return subProjects;
}
public void setSubProjects(List<Project> subProjects) {
this.subProjects = subProjects;
}
public void addSubProject(Project subProject) {
subProjects.add(subProject);
}
public int getHoursDone() {
return getSubProjects().stream().map(project -> project.getHoursDone()).reduce(0, Integer::sum);
}
public Date getLastModified() {
return getSubProjects().stream().map(project -> project.getLastModified()).max(Date::compareTo).orElse(null);
}
}
// Second POJO for easy binding
public class LeafProject extends Project {
private int hoursDone;
private Date lastModified;
public LeafProject(String name, int hoursDone, int year) {
super(name);
this.hoursDone = hoursDone;
lastModified = new Date(year - 1900, random.nextInt(12), random.nextInt(10));
}
@Override
public int getHoursDone() {
return hoursDone;
}
@Override
public Date getLastModified() {
return lastModified;
}
}
}
接下来,递归展开或折叠节点有点取决于您的场景,但基本上它分解为同一件事:确保从根到最深叶的每个节点都是 expanded/collapsed。最简单的这样做的方法是 将您的层次结构展平 到节点列表中,然后调用适当的方法 expand(List<T> items)
或 expand(T ... items)
(第二个代表第一个和可能是一种方便的方法,例如 expand(myItem)
).
为简单起见,我在 Project
实现中添加了一个 flatten
方法。如果由于某种原因您不能这样做,则创建一个递归方法,该方法创建一个列表,该列表从所选节点开始并包括所有子节点,子节点的,子节点的……好吧,您明白了。
public Stream<Project> flatten() {
return Stream.concat(Stream.of(this), getSubProjects().stream().flatMap(Project::flatten));
}
可能的场景:
- 展开根时自动展开整个层级 - 添加监听器,expand/collapse整个展平层级:
treeGrid.addCollapseListener(event -> {
if (event.isUserOriginated()) {
// event is triggered by all collapse calls, so only do it the first time, when the user clicks in the UI
// and ignore the programmatic calls
treeGrid.collapse(event.getCollapsedItem().flatten().collect(Collectors.toList()));
}
});
treeGrid.addExpandListener(event -> {
if (event.isUserOriginated()) {
// event is triggered by all expand calls, so only do it the first time, when the user clicks in the UI
// and ignore the programmatic calls
treeGrid.expand(event.getExpandedItem().flatten().collect(Collectors.toList()));
}
});
- 使用上下文菜单等自定义操作扩展层次结构或其中的一部分
GridContextMenu<Project> contextMenu = new GridContextMenu<>(treeGrid);
contextMenu.addGridBodyContextMenuListener(contextEvent -> {
contextMenu.removeItems();
if (contextEvent.getItem() != null) {
Project project = (Project) contextEvent.getItem();
// update selection
treeGrid.select(project);
// show option for expanding
contextMenu.addItem("Expand all", VaadinIcons.PLUS, event -> treeGrid.expand((project).flatten().collect(Collectors.toList())));
// show option for collapsing
contextMenu.addItem("Collapse all", VaadinIcons.MINUS, event -> treeGrid.collapse((project).flatten().collect(Collectors.toList())));
}
});
最后你应该得到这样的效果:
Vaadin 8.1 引入了 TreeGrid
组件。它不再有 collapseItemsRecursively
和 expandItemsRecursively
方法(在现在的遗留 Tree
组件中可用)。我错过了什么或者你需要开发自己的实现吗?如果是这样,推荐的方法是什么?
来自 docs for treegrid, you can use the methods, collapse
and expand
,通过传递树状网格数据项的列表或数组来展开或折叠:
treeGrid.expand(someTreeGridItem1, someTreeGridItem2);
treeGrid.collapse(someTreeGridItem1);
同样值得注意的是,显示 prevent certain items from ever being collapsed
能力的部分我相信您已经注意到,TreeGrid 是一个相当新的组件,目前正在开发中,从 v8 开始可用。1.alphaX(当前的稳定版本是 v8.0.6)。因此,它目前可能只有一些基本功能,其余的将在未来的某个时候推出,尽管不能保证。例如 this similar feature request for the older TreeTable component 自 2011 年以来一直处于开放状态。
无论哪种方式,即使它们可能不是最佳解决方案,您也可以使用一些解决方法来实现此行为。我 无耻地 将 vaadin-sampler for TreeGrid.
当前可用代码的略微修改版本用作基本示例public class RecursiveExpansionTreeGrid extends VerticalLayout {
private Random random = new Random();
public RecursiveExpansionTreeGrid() {
// common setup with some dummy data
TreeGrid<Project> treeGrid = new TreeGrid<>();
treeGrid.setItems(generateProjectsForYears(2010, 2016), Project::getSubProjects);
treeGrid.addColumn(Project::getName).setCaption("Project Name").setId("name-column");
treeGrid.addColumn(Project::getHoursDone).setCaption("Hours Done");
treeGrid.addColumn(Project::getLastModified).setCaption("Last Modified");
addComponent(treeGrid);
}
// generate some dummy data to display in the tree grid
private List<Project> generateProjectsForYears(int startYear, int endYear) {
List<Project> projects = new ArrayList<>();
for (int year = startYear; year <= endYear; year++) {
Project yearProject = new Project("Year " + year);
for (int i = 1; i < 2 + random.nextInt(5); i++) {
Project customerProject = new Project("Customer Project " + i);
customerProject.setSubProjects(Arrays.asList(
new LeafProject("Implementation", random.nextInt(100), year),
new LeafProject("Planning", random.nextInt(10), year),
new LeafProject("Prototyping", random.nextInt(20), year)));
yearProject.addSubProject(customerProject);
}
projects.add(yearProject);
}
return projects;
}
// POJO for easy binding
public class Project {
private List<Project> subProjects = new ArrayList<>();
private String name;
public Project(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Project> getSubProjects() {
return subProjects;
}
public void setSubProjects(List<Project> subProjects) {
this.subProjects = subProjects;
}
public void addSubProject(Project subProject) {
subProjects.add(subProject);
}
public int getHoursDone() {
return getSubProjects().stream().map(project -> project.getHoursDone()).reduce(0, Integer::sum);
}
public Date getLastModified() {
return getSubProjects().stream().map(project -> project.getLastModified()).max(Date::compareTo).orElse(null);
}
}
// Second POJO for easy binding
public class LeafProject extends Project {
private int hoursDone;
private Date lastModified;
public LeafProject(String name, int hoursDone, int year) {
super(name);
this.hoursDone = hoursDone;
lastModified = new Date(year - 1900, random.nextInt(12), random.nextInt(10));
}
@Override
public int getHoursDone() {
return hoursDone;
}
@Override
public Date getLastModified() {
return lastModified;
}
}
}
接下来,递归展开或折叠节点有点取决于您的场景,但基本上它分解为同一件事:确保从根到最深叶的每个节点都是 expanded/collapsed。最简单的这样做的方法是 将您的层次结构展平 到节点列表中,然后调用适当的方法 expand(List<T> items)
或 expand(T ... items)
(第二个代表第一个和可能是一种方便的方法,例如 expand(myItem)
).
为简单起见,我在 Project
实现中添加了一个 flatten
方法。如果由于某种原因您不能这样做,则创建一个递归方法,该方法创建一个列表,该列表从所选节点开始并包括所有子节点,子节点的,子节点的……好吧,您明白了。
public Stream<Project> flatten() {
return Stream.concat(Stream.of(this), getSubProjects().stream().flatMap(Project::flatten));
}
可能的场景:
- 展开根时自动展开整个层级 - 添加监听器,expand/collapse整个展平层级:
treeGrid.addCollapseListener(event -> {
if (event.isUserOriginated()) {
// event is triggered by all collapse calls, so only do it the first time, when the user clicks in the UI
// and ignore the programmatic calls
treeGrid.collapse(event.getCollapsedItem().flatten().collect(Collectors.toList()));
}
});
treeGrid.addExpandListener(event -> {
if (event.isUserOriginated()) {
// event is triggered by all expand calls, so only do it the first time, when the user clicks in the UI
// and ignore the programmatic calls
treeGrid.expand(event.getExpandedItem().flatten().collect(Collectors.toList()));
}
});
- 使用上下文菜单等自定义操作扩展层次结构或其中的一部分
GridContextMenu<Project> contextMenu = new GridContextMenu<>(treeGrid);
contextMenu.addGridBodyContextMenuListener(contextEvent -> {
contextMenu.removeItems();
if (contextEvent.getItem() != null) {
Project project = (Project) contextEvent.getItem();
// update selection
treeGrid.select(project);
// show option for expanding
contextMenu.addItem("Expand all", VaadinIcons.PLUS, event -> treeGrid.expand((project).flatten().collect(Collectors.toList())));
// show option for collapsing
contextMenu.addItem("Collapse all", VaadinIcons.MINUS, event -> treeGrid.collapse((project).flatten().collect(Collectors.toList())));
}
});
最后你应该得到这样的效果: