在单元格中动态添加小部件以表示"标记"在Datagrid中

时间:2017-04-28 13:23:36

标签: gwt datagrid widget custom-cell

在GWT Web应用程序中,我使用DataGrid来管理数据库中的元素。我将元素列表表示为行,列是其特征的可编辑字段(id,name,description)。我主要使用的是EditTextCell类。

我现在想为一个必须代表"标签列表的列创建一个自定义单元格。可以附加到每个元素。从这个单元格中,可以添加标签,使用+按钮(显示下拉菜单或其他内容),并删除。每个标签应该是一种按钮或交互式小部件(我后来想要显示弹出信息,触发操作等)。

实际上,它与"标签并没有那么不同。 Stack Overflow网站上的栏...

enter image description here

所以我一直在寻找解决方案:

  • 我觉得这很容易做到。我想象只是将FlowPanel放在单元格中,动态添加/删除Buttons / Widgets。但事实证明,在GWT Widgets和Cells以及非常不同的对象中显然......

  • 我读过使用AbstractCell类来创建一个允许做任何事情的自定义单元格,但它的工作水平很低,对我来说很模糊。

  • 我看到CompositeCell允许将各种单元格小部件组合到一个单元格中,但我还没有发现是否可以动态地执行它,或者是否整个列中的所有行的小部件都相同。我大多看到了一些例子,例如,如何在一列的每个单元格中放置两个按钮。

实现我需要的最简单方法是什么?

编辑:

因此,经过一些测试后,我会选择安德烈的建议,然后进入低级别",创建一个扩展AbstractCell<>的自定义单元格。我可以创建一个合适的"渲染" function,它生成一个html" button"的列表,并在触发Javascript事件时将Javascript调用附加到我的Java函数(onclick,onmouseover,onmouseout ......)。

工作得很好。例如,点击" +"按钮最后是一个标签列表,它调用一个MenuBar小部件,显示可以添加的标签列表。

但是我在努力寻找一种在添加标签时更新基础数据的方法。

总结一下:

  • 我有一个CustomData类,它表示我想在表格的每一行显示的数据。它还包含标记列表作为Set。
  • ModelTable(扩展DataGrid)是我的表。
  • CustomCell(扩展AbstractCell)可以将标签列表呈现为一行上的多个按钮。
  • 点击" +"单元格中的按钮会生成一个AddTagMenu弹出窗口,我可以从中单击要添加的标记。

enter image description here

如何更新单元格的内容?

我尝试使用onBrowserEvent,onEnterKeyDown,总线事件......但没有成功。最好我确实可以在底层对象中添加一个标记元素,但是表格不会更新。

2 个答案:

答案 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

enter image description here