Gwt 在单元格中动态添加小部件以表示;标签;在数据网格中

Gwt 在单元格中动态添加小部件以表示;标签;在数据网格中,gwt,datagrid,widget,custom-cell,Gwt,Datagrid,Widget,Custom Cell,在GWT web应用程序中,我使用DataGrid来管理数据库中的元素。我将元素列表表示为行,列是其特征(id、名称、描述)的可编辑字段。我主要使用EditTextCell类 现在我想为一列创建一个自定义单元格,该列必须表示可以附加到每个元素的“标记”列表。从这个单元格中,可以使用+按钮(显示下拉菜单或其他)添加和删除标记。每个标签都应该是一种按钮或交互式小部件(稍后我想显示带有信息、触发动作等的弹出窗口) 实际上,它与Stack Overflow网站上的“tags”栏没有太大区别 因此,我一

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

现在我想为一列创建一个自定义单元格,该列必须表示可以附加到每个元素的“标记”列表。从这个单元格中,可以使用+按钮(显示下拉菜单或其他)添加和删除标记。每个标签都应该是一种按钮或交互式小部件(稍后我想显示带有信息、触发动作等的弹出窗口)

实际上,它与Stack Overflow网站上的“tags”栏没有太大区别

因此,我一直在寻找解决方案:

  • 我想这很容易做到。我想象着在单元格中放置一个FlowPanel,动态添加/删除按钮/小部件。但事实证明,在GWT小部件、单元格和非常不同的对象中

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

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

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


编辑:

所以,在一些测试之后,我将接受Andrei的建议,进行“低级别”,创建一个扩展AbstractCell的自定义单元格。我可以创建一个适当的“render”函数,生成一个html“button”列表,并在触发Javascript事件(onclick、onmouseover、onmouseout…)时将Javascript调用附加到我的Java函数

它运行得很好。例如,通过单击标记列表末尾的“+”按钮,它将调用一个菜单栏小部件,显示可以添加的标记列表

但是,我正在努力寻找一种在添加标记时更新底层数据的方法

总而言之:

  • 我有一个CustomData类,它表示我希望在表的每一行中显示的数据。它还包含作为一个集合的标记列表
  • ModelTable(扩展DataGrid)是我的表
  • CustomCell(extends AbstractCell)可以将标记列表呈现为一行中的多个按钮
  • 单击单元格中的“+”按钮将生成AddTagMenu弹出式下拉菜单,我可以从中单击要添加的标记

如何更新单元格的内容


我试着玩onBrowserEvent、OneInterkeyDown、总线事件。。。没有成功。充其量,我确实可以向底层对象添加一个标记元素,但该表不会更新。

如果不达到您所称的“低级别”,就不可能满足您的要求

创建一个单元格,使其能够完全按照您的需要呈现标记,这是相对容易的。如果这是单元格上的唯一操作,则Plus图标也很容易。但是,很难使单元格中的每个标记都成为交互式小部件,因为DataGrid不允许将处理程序附加到单元格中呈现的HTML。您需要为这些小部件提供自己的ID,然后在代码中为它们附加处理程序。然而,问题是,当DataGrid刷新/重新呈现时,处理程序很可能会丢失。因此,在DataGrid的每次更改中,必须将它们再次附加到每个单元格中的每个标记


一种更简单的方法是创建一个表示“行”的复合小部件,然后将这些“行”添加到FlowPanel中。您可以很容易地使它看起来像一个带有CSS的表,并提供您自己的类似于表头的小部件。您将需要重新创建DataGrid的一些功能,例如,单击“列”标题时进行排序-当然,如果您需要此功能。

正如您已经指出的,使用
CompositeCell
可能是获得所需内容的一种方法

其思想是为每个标记创建一个单元格,然后(在渲染期间)决定应该显示(渲染)哪个标记。最后,通过创建一个
CompositeCell
将所有这些单元格合并为一个单元格

此解决方案的主要缺点是,在创建
DataGrid
之前,您需要知道所有可能的标记

因此,如果您有一个固定的可能标签列表,或者可以得到一个所有现有标签的列表,并且这个列表相当小,那么这里有一个解决方案。


首先,我们需要知道哪个标记由一列表示,因此我扩展了
类来保存关于标记的信息。请注意,单击按钮时,
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();
    }
}
现在,最重要的部分是:决定是否显示标记-覆盖
CompositeCell的
render
方法:

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>");
    }
};

你好,亚当。非常感谢你的回答。我测试了这个想法,但我发现了两个问题:-可能的标签数量实际上可能会增加很多。肯定有几十个,可能有几百个。表格可能需要同时显示数百行。所以我需要看看它的行为可能的标记是固定的,但是在数据库中,一些用户可以创建新的标记。所以我不能使用枚举。但是我想我可以解决这个问题。这个解决方案不需要固定的标签列表。一个数据库中是否有数千个标记并不重要,您只需要知道呈现的表中可能的标记的列表。换句话说,您可以将(TagEnum标记:TagEnum.values())的
替换为(String标记:tagsOnThisPage)
谢谢Andrei。你能告诉那个swi吗
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>");
    }
};
private DataGrid<DataType> getGrid() {
    DataGrid<DataType> grid = new DataGrid<DataType>();

    List<HasCell<DataType, ?>> tagColumns = new ArrayList<HasCell<DataType, ?>>();
    for(TagEnum tag : TagEnum.values())
        tagColumns.add(new TagColumn(tag));

    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>");
        }
    };

    Column<DataType, DataType> tagsColumn = new Column<DataType, DataType>(tagsCell) {
        @Override
        public DataType getValue(DataType object) {
            return object;
        }
    };

    grid.addColumn(tagsColumn, "Tags");

    grid.setRowData(Arrays.asList(
            new DataType(Arrays.asList(TagEnum.gwt)), 
            new DataType(Arrays.asList(TagEnum.table, TagEnum.datagrid)), 
            new DataType(Arrays.asList(TagEnum.datagrid, TagEnum.widget, TagEnum.customCell)), 
            new DataType(Arrays.asList(TagEnum.gwt, TagEnum.table, TagEnum.widget, TagEnum.customCell)), 
            new DataType(Arrays.asList(TagEnum.gwt, TagEnum.customCell)), 
            new DataType(Arrays.asList(TagEnum.gwt, TagEnum.table, TagEnum.datagrid, TagEnum.widget, TagEnum.customCell))
        )
    );

    return grid;
}

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();
    }
}

public class DataType {
    List<TagEnum> tagList;

    public DataType(List<TagEnum> tagList) {
        this.tagList = tagList;
    }

    public List<TagEnum> getTagList() {
        return tagList;
    }
}

public enum TagEnum {
    gwt         ("gwt"),
    table       ("table"),
    datagrid    ("datagrid"),
    widget      ("widget"),
    customCell  ("custom-cell");

    private String name;

    private TagEnum(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}