在GWT Web应用程序中,我使用DataGrid来管理数据库中的元素。我将元素列表表示为行,列是其特征的可编辑字段(id,name,description)。我主要使用的是EditTextCell类。
我现在想为一个必须代表"标签列表的列创建一个自定义单元格。可以附加到每个元素。从这个单元格中,可以添加标签,使用+按钮(显示下拉菜单或其他内容),并删除。每个标签应该是一种按钮或交互式小部件(我后来想要显示弹出信息,触发操作等)。
实际上,它与"标签并没有那么不同。 Stack Overflow网站上的栏...
所以我一直在寻找解决方案:
我觉得这很容易做到。我想象只是将FlowPanel放在单元格中,动态添加/删除Buttons / Widgets。但事实证明,在GWT Widgets和Cells以及非常不同的对象中显然......
我读过使用AbstractCell类来创建一个允许做任何事情的自定义单元格,但它的工作水平很低,对我来说很模糊。
我看到CompositeCell允许将各种单元格小部件组合到一个单元格中,但我还没有发现是否可以动态地执行它,或者是否整个列中的所有行的小部件都相同。我大多看到了一些例子,例如,如何在一列的每个单元格中放置两个按钮。
实现我需要的最简单方法是什么?
编辑:
因此,经过一些测试后,我会选择安德烈的建议,然后进入低级别",创建一个扩展AbstractCell<>的自定义单元格。我可以创建一个合适的"渲染" function,它生成一个html" button"的列表,并在触发Javascript事件时将Javascript调用附加到我的Java函数(onclick,onmouseover,onmouseout ......)。
工作得很好。例如,点击" +"按钮最后是一个标签列表,它调用一个MenuBar小部件,显示可以添加的标签列表。
但是我在努力寻找一种在添加标签时更新基础数据的方法。
总结一下:
如何更新单元格的内容?
我尝试使用onBrowserEvent,onEnterKeyDown,总线事件......但没有成功。最好我确实可以在底层对象中添加一个标记元素,但是表格不会更新。
答案 0 :(得分:1)
如果你没有真正“低级别”,就不可能满足你的要求。
创建一个能够完全按照您想要的方式呈现标签的单元格相对容易。如果这是对单元格的唯一操作,那么加号图标也很容易。但是,很难将单元格中的每个标记都设置为交互式窗口小部件,因为DataGrid不允许您将处理程序附加到单元格内呈现的HTML。您需要为这些小部件提供自己的ID,然后在代码中将处理程序附加到它们。但问题是,当DataGrid刷新/重新渲染时,您的处理程序很可能会丢失。因此,在DataGrid中的每次更改时,您都必须将它们再次附加到每个单元格中的每个标记。
更简单的方法是创建表示“行”的复合窗口小部件,然后将这些“行”添加到FlowPanel。您可以轻松地使它看起来像一个带有CSS的表,并提供看起来像表头的自己的小部件。您需要重新创建DataGrid的一些功能,例如单击“列”标题时排序 - 当然,如果您需要此功能。
答案 1 :(得分:1)
正如您已经指出的那样,使用CompositeCell
可以获得您想要的效果。
我们的想法是为每个标签创建一个单元格,然后(在渲染过程中)决定应该显示哪一个(渲染)。最后,通过创建CompositeCell
将所有这些单元格合并为一个。
此解决方案的主要缺点是您需要在创建DataGrid
之前了解所有可能的标记。
因此,如果您有可能标记的固定列表,或者可以获得所有现有标记的列表,并且此列表相当小,则可以使用此解决方案。
首先,我们需要知道哪个标记由列表示,因此我扩展了Column
类以保留有关标记的信息。请注意,TagColumn
使用ButtonCell
并在点击按钮时处理update
:
public class TagColumn extends Column<DataType, String> {
private TagEnum tag;
public TagColumn(TagEnum tag) {
super(new ButtonCell());
this.tag = tag;
setFieldUpdater(new FieldUpdater<DataType, String>() {
@Override
public void update(int index, DataType object, String value) {
Window.alert("Tag " + getTag().getName() + " clicked");
}
});
}
public TagEnum getTag() {
return tag;
}
@Override
public String getValue(DataType object) {
return tag.getName();
}
}
然后为每个标签创建一个单元格(我在TagEnum
中对所有标签进行了硬编码):
List<HasCell<DataType, ?>> tagColumns = new ArrayList<HasCell<DataType, ?>>();
for(TagEnum tag : TagEnum.values())
tagColumns.add(new TagColumn(tag));
现在,最重要的部分:决定是否显示标记 - 覆盖render
的{{1}}方法:
CompositeCell
这对于始终呈现任何元素(例如,不应显示标记时为空CompositeCell<DataType> tagsCell = new CompositeCell<DataType>(tagColumns) {
@Override
protected <X> void render(Context context, DataType value, SafeHtmlBuilder sb, HasCell<DataType, X> hasCell) {
if(value.getTagList().contains(((TagColumn) hasCell).getTag()))
super.render(context, value, sb, hasCell);
else
sb.appendHtmlConstant("<span></span>");
}
};
)非常重要。否则,在访问兄弟元素时,span
的实现会变得混乱。
最后,完整的,有效的示例代码:
CompositeCell