java 列数可变的检票表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5500308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 11:25:31  来源:igfitidea点击:

Wicket table with variable number of columns

javawicket

提问by Mario Duarte

I've been creating tables by adding a ListView(providing it with my data as a List<MyObject>) to the page, and assigning the corresponding ids to each column in the html file.

我一直在通过向页面添加 a ListView(将我的数据作为 a 提供给它List<MyObject>)来创建表格,并将相应的 id 分配给 html 文件中的每一列。

However now I have a situation where instead of a simple List<MyObject>I have List<Map<String,MyObject>>. I also get a list with all the possible keys of the nested map (List<String>). Now I need to create a table where each value of the Mapshould be in the column with the name of the key pointing to that value.

但是现在我有一个情况,而不是一个简单的List<MyObject>我有List<Map<String,MyObject>>. 我还得到了一个包含嵌套映射 ( List<String>) 的所有可能键的列表。现在我需要创建一个表,其中的每个值都Map应该在键名指向该值的列中。

Let's say I have the following data:

假设我有以下数据:

keys = ['a', 'b']

data = [ { 'a' = 1, 'b' = 2 },
         { 'a' = 3, 'b' = 4 },
         { 'a' = 5, 'b' = 6}] 

I would like to create the table:

我想创建表:

<table>
    <tr>
        <th>a</th>
        <th>b</th>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
    </tr>
    <tr>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>5</td>
        <td>6</td>
    </tr>
</table>

Knowing that the names and number of keys in the nested Map can change, what is the best way to implement this in wicket?

知道嵌套 Map 中键的名称和数量可以更改,在 wicket 中实现这一点的最佳方法是什么?

回答by tetsuo

Below, examples using DefaultDataTable and nested ListViews.

下面是使用 DefaultDataTable 和嵌套 ListViews 的示例。

Note that, while the DataTable approach may look less straightforward (well, it depends on the eye of the beholder), it actually separates more cleanly data fetching from visualization, and you get pagination out-of-the-box: try adding more data, or lowering the rowsPerPage(DefaultDataTable's last constructor param).

请注意,虽然 DataTable 方法可能看起来不那么直接(好吧,这取决于旁观者的眼睛),但它实际上将更清晰的数据获取与可视化分开,并且您可以开箱即用地进行分页:尝试添加更多数据,或降低rowsPerPage(DefaultDataTable 的最后一个构造函数参数)。

public class HomePage extends WebPage {

    static final String A = "a";
    static final String B = "b";

    public HomePage() {
        final List<String> keys = Arrays.asList(A, B);
        final List<Map<String, Integer>> data = Arrays.asList(
            map(A, 1).put(B, 11).toMap(),
            map(A, 2).put(B, 12).toMap(),
            map(A, 3).put(B, 13).toMap(),
            map(A, 4).put(B, 14).toMap(),
            map(A, 5).put(B, 15).toMap(),
            map(A, 6).put(B, 16).toMap(),
            map(A, 7).put(B, 17).toMap(),
            map(A, 8).put(B, 18).toMap(),
            map(A, 9).put(B, 19).toMap());

        // Using a DefaultDataTable
        ISortableDataProvider dataProvider = new SortableDataProvider() {
            public Iterator iterator(int first, int count) {
                int start = Math.min(0, first);
                int end = Math.min(data.size(), start + count);
                return data.subList(start, end).iterator();
            }
            public int size() {
                return data.size();
            }
            public IModel model(Object object) {
                return new CompoundPropertyModel(object);
            }
        };
        List columns = new ArrayList();
        for (String key : keys)
            columns.add(new PropertyColumn(Model.of(key), key));
        add(new DefaultDataTable("dataTable", columns, dataProvider, 20));

        // Using a nested ListViews
        add(new ListView("headers", keys) {
            @Override
            protected void populateItem(ListItem item) {
                item.add(new Label("header", String.valueOf(item.getModelObject())));
            }
        });
        add(new ListView("listView", data) {
            @Override
            protected void populateItem(ListItem item) {
                final Map rowMap = (Map) item.getModelObject();
                item.add(new ListView("nested", keys) {
                    @Override
                    protected void populateItem(ListItem item) {
                        Object value = rowMap.get(item.getModelObject());
                        item.add(new Label("value", String.valueOf(value)));
                    }
                });
            }
        });
    }

    // to make building the data structure a little more fun :)
    private MapBuilder<String, Integer> map(String key, Integer value) {
        return new MapBuilder<String, Integer>().put(key, value);
    }
    private static class MapBuilder<K, V> {
        Map<K, V> map = new HashMap<K, V>();
        MapBuilder<K, V> put(K key, V value) {
            map.put(key, value);
            return this;
        }
        Map<K, V> toMap() {
            return map;
        }
    }
}


<html xmlns:wicket="http://wicket.apache.org">
<body>

  <table wicket:id="dataTable"></table>

  <table>
    <tr>
      <th wicket:id="headers">
          <span wicket:id="header"></span>
      </th>
    </tr>
    <tr wicket:id="listView">
      <td wicket:id="nested">
        <span wicket:id="value"></span>
      </td>
    </tr>
  </table>

</body>
</html>

回答by Adrian Cox

You can nest ListView. The markup you want will look something like this:

你可以嵌套ListView。您想要的标记如下所示:

<table>
  <tr><th wicket:id="headerlist"><span wicket:id="header"></span></th></tr>
  <tr wicket:id="contentlist"><td wicket:id="column">
    <span wicket:id="data"></span>
  </td></tr>
</table>

You will then need three ListView. The first (headerlist) will fill in the headers from the keyslist. This is simple, so I'll skip the example.

然后你需要三个ListView。第一个 ( headerlist) 将填充keys列表中的标题。这很简单,所以我将跳过这个例子。

The second (contentlist) will be across your datalist. In the populateItemsmethod you will add the third ListView(column), which will again iterate across the keyslist:

第二个 ( contentlist) 将出现在您的data列表中。在该populateItems方法中,您将添加第三个ListView( column),它将再次遍历keys列表:

add(new ListView<Map<String,MyObject>>("contentlist", data) {
  protected void populateItem(ListItem<Map<String,MyObject>> item) {
    final Map<String,MyObject> map = item.getModelObject();
    // Inner list - using item.add to add to the inner list
    item.add(new ListView<String>("column", keys) {
      protected void populateItem(ListItem<String> item) {
        String key = item.getModelObject();
        item.add(new Label("data", map.get(key).toString()));
      }
    });
  }
});

回答by biziclop

You can of course use nested ListViews, but you can also use DataTableand its descendants, which were specifically designed for this task. As a bonus you can also get things like sorting and pagination out of them.

您当然可以使用嵌套的ListViews,但您也可以使用 sDataTable及其后代,它们是专门为此任务设计的。作为奖励,您还可以获得诸如排序和分页之类的东西。

回答by Rick O'Sullivan

Thanks Tetsuo! I've filled in the Generics for Tetsuo's variable column examples:

谢谢哲雄!我已经为 Tetsuo 的变量列示例填写了泛型:

  1. DefaultDataTable
  2. Nested ListViews
  1. 默认数据表
  2. 嵌套列表视图

Wicket HTML

检票口 HTML

<html xmlns:wicket="http://wicket.apache.org">
<body>

  <h3>Example 1</h3>
  <table wicket:id="dataTable"></table>

  <br>

  <h3>Example 2</h3>
  <table>

    <tr>
      <th wicket:id="headers">
        <span wicket:id="header"></span>
      </th>
    </tr>

    <tr wicket:id="listView">
      <td wicket:id="nested">
        <span wicket:id="value"></span>
      </td>
    </tr>

  </table>

</body>
</html>

Wicket Java

检票口爪哇

public class HomePage extends WebPage 
{
    /** Represents serialVersionUID. */
    private static final long serialVersionUID = 20150701L;

    static final String A = "alpha";
    static final String B = "beta";
    static final String C = "gamma";

    public HomePage()
    {
        super();

        final List<String> keys = Arrays.asList(A, B, C);

        final List<Map<String,Integer>> data = Arrays.asList
        (
            map(A, 1).put(B, 11).put(C, 21).toMap(),
            map(A, 2).put(B, 12).put(C, 22).toMap(),
            map(A, 3).put(B, 13).put(C, 23).toMap(),
            map(A, 4).put(B, 14).put(C, 24).toMap(),
            map(A, 5).put(B, 15).put(C, 25).toMap(),
            map(A, 6).put(B, 16).put(C, 26).toMap(),
            map(A, 7).put(B, 17).put(C, 27).toMap(),
            map(A, 8).put(B, 18).put(C, 28).toMap(),
            map(A, 9).put(B, 19).put(C, 29).toMap()
        );

        // Using a DefaultDataTable
        ISortableDataProvider<Map<String,Integer>,String> dataProvider = 
            new SortableDataProvider<Map<String,Integer>,String>()
        {
            /** Represents serialVersionUID. */
            private static final long serialVersionUID = HomePage.serialVersionUID;

            public Iterator<Map<String,Integer>> iterator(long first, long count)
            {
                int start = Math.max(0, (int) first);
                int end = Math.min(data.size(), start + (int) count);
                return data.subList(start, end).iterator();
            }

            public long size()
            {
                return data.size();
            }

            public IModel<Map<String,Integer>> model(Map<String,Integer> object)
            {
                return new CompoundPropertyModel<Map<String,Integer>>(object);
            }
        };

        List<PropertyColumn<Map<String,Integer>,String>> columns =
            new ArrayList<PropertyColumn<Map<String,Integer>,String>>();

        for (String key : keys)
            columns.add(new PropertyColumn<Map<String,Integer>,String>(Model.of(key), key));

        // Example 1 - Using a DataTable
        // Wicket: "dataTable"
        add(new DefaultDataTable<Map<String,Integer>,String>("dataTable", columns, dataProvider, 5));

        // Example 2 - Using nested ListViews
        // Wicket: "headers"
        add
        (
            new ListView<String>("headers", keys)
            {
                /** Represents serialVersionUID. */
                private static final long serialVersionUID = HomePage.serialVersionUID;

                @Override
                protected void populateItem(ListItem<String> item)
                {
                    // Wicket: "header"
                    item.add(new Label("header", String.valueOf(item.getModelObject())));
                }
            }
        );

        add
        (
            // Wicket: "listView"
            new ListView<Map<String,Integer>>("listView", data)
            {
                /** Represents serialVersionUID. */
                private static final long serialVersionUID = HomePage.serialVersionUID;

                @Override
                protected void populateItem(ListItem<Map<String,Integer>> item)
                {
                    final Map<String,Integer> rowMap = item.getModelObject();
                    item.add
                    (
                        // Wicket: "nested"
                        new ListView<String>("nested", keys)
                        {
                            private static final long serialVersionUID = HomePage.serialVersionUID;
                            @Override
                            protected void populateItem(ListItem<String> item)
                            {
                                Integer value = rowMap.get(item.getModelObject());

                                // Wicket: "value"
                                item.add(new Label("value", String.valueOf(value)));
                            }
                        }
                    );
                }
            }
        );
    }

    // Make building the data structure a little more fun :)
    private MapBuilder<String, Integer> map(String key, Integer value)
    {
        return new MapBuilder<String, Integer>().put(key, value);
    }

    private static class MapBuilder<K, V>
    {
        Map<K, V> map = new HashMap<K, V>();

        MapBuilder<K, V> put(K key, V value)
        {
            map.put(key, value);
            return this;
        }

        Map<K, V> toMap()
        {
            return map;
        }
    }
}

Generic Usage

通用用法

DefaultDataTable extends DataTable

DefaultDataTable 扩展了 DataTable

  • @param The model object type
  • @param The type of the sorting parameter
  • @param 模型对象类型
  • @param 排序参数的类型

IColumn

专栏

  • @param The type of the object that will be rendered in this column's cells
  • @param The type of the sorting parameter
  • @param 将在此列的单元格中呈现的对象的类型
  • @param 排序参数的类型

ISortableDataProvider

ISortableDataProvider

  • @param The model object type (omitted in JavaDoc) ??
  • @param The type of the sorting parameter
  • @param 模型对象类型(JavaDoc 中省略) ??
  • @param 排序参数的类型