UiCellTable

单元格表格(数据展示表格)提供高性能渲染,以表格视图展示大型数据集。您可以查看 GWT 展示中的 单元格表格示例 来了解其工作原理。

本开发者指南将带您了解特定于单元格表格的一些高级功能,例如列排序。如果您不熟悉单元格小部件,请在继续之前阅读 单元格小部件开发者指南

  1. 列排序
  2. 控制列宽

列排序

单元格表格内置了对列排序的支持。使用 Column.setSortable(boolean) 使列可排序。用户随后可以点击列标题并触发 ColumnSortEvent。您如何处理事件取决于您如何将数据推送到单元格表格中。

使用 ListDataProvider 进行列排序

GWT 提供了 ColumnSortEvent.Handler 的默认实现,称为 ColumnSortEvent.ListHandler,它旨在对 java.util.List 执行本地排序。

代码示例 - 下面的示例向使用 ListDataProvider 支持的单元格表格添加了列排序支持。

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class CellTableExample implements EntryPoint {
  // A simple data type that represents a contact.
  private static class Contact {
    private final String address;
    private final String name;

    public Contact(String name, String address) {
      this.name = name;
      this.address = address;
    }
  }

  // The list of data to display.
  private static List<Contact> CONTACTS = Arrays.asList(new Contact("John",
      "123 Fourth Road"), new Contact("Mary", "222 Lancer Lane"), new Contact(
      "Zander", "94 Road Street"));

  public void onModuleLoad() {

    // Create a CellTable.
    CellTable<Contact> table = new CellTable<Contact>();

    // Create name column.
    TextColumn<Contact> nameColumn = new TextColumn<Contact>() {
      @Override
      public String getValue(Contact contact) {
        return contact.name;
      }
    };

    // Make the name column sortable.
    nameColumn.setSortable(true);

    // Create address column.
    TextColumn<Contact> addressColumn = new TextColumn<Contact>() {
      @Override
      public String getValue(Contact contact) {
        return contact.address;
      }
    };

    // Add the columns.
    table.addColumn(nameColumn, "Name");
    table.addColumn(addressColumn, "Address");

    // Create a data provider.
    ListDataProvider<Contact> dataProvider = new ListDataProvider<Contact>();

    // Connect the table to the data provider.
    dataProvider.addDataDisplay(table);

    // Add the data to the data provider, which automatically pushes it to the
    // widget.
    List<Contact> list = dataProvider.getList();
    for (Contact contact : CONTACTS) {
      list.add(contact);
    }

    // Add a ColumnSortEvent.ListHandler to connect sorting to the
    // java.util.List.
    ListHandler<Contact> columnSortHandler = new ListHandler<Tester.Contact>(
        list);
    columnSortHandler.setComparator(nameColumn,
        new Comparator<Tester.Contact>() {
          public int compare(Contact o1, Contact o2) {
            if (o1 == o2) {
              return 0;
            }

            // Compare the name columns.
            if (o1 != null) {
              return (o2 != null) ? o1.name.compareTo(o2.name) : 1;
            }
            return -1;
          }
        });
    table.addColumnSortHandler(columnSortHandler);

    // We know that the data is sorted alphabetically by default.
    table.getColumnSortList().push(nameColumn);

    // Add it to the root panel.
    RootPanel.get().add(table);
  }
}

使用 AsyncDataProvider 进行列排序

GWT 提供了 ColumnSortEvent.Handler 的默认实现,称为 ColumnSortEvent.AsyncHandler,它有助于异步(服务器端)列排序。当用户对列进行排序时,AsyncHandler 会调用 HasData.setVisibleRangeAndClearData(Range, boolean),这会向 AsyncDataProvider 触发 RangeChangeEvent。

代码示例 - 下面的示例向使用 AsyncDataProvider 支持的单元格表格添加了列排序支持。

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class CellTableExample implements EntryPoint {

  // A simple data type that represents a contact.
  private static class Contact {
    private final String address;
    private final String name;

    public Contact(String name, String address) {
      this.name = name;
      this.address = address;
    }
  }

  // The list of data to display.
  private static List<Contact> CONTACTS = Arrays.asList(new Contact("John",
      "123 Fourth Road"), new Contact("Mary", "222 Lancer Lane"), new Contact(
      "Zander", "94 Road Street"));

  public void onModuleLoad() {

    // Create a CellTable.
    final CellTable<Contact> table = new CellTable<Contact>();

    // Create name column.
    TextColumn<Contact> nameColumn = new TextColumn<Contact>() {
      @Override
      public String getValue(Contact contact) {
        return contact.name;
      }
    };

    // Make the name column sortable.
    nameColumn.setSortable(true);

    // Create address column.
    TextColumn<Contact> addressColumn = new TextColumn<Contact>() {
      @Override
      public String getValue(Contact contact) {
        return contact.address;
      }
    };

    // Add the columns.
    table.addColumn(nameColumn, "Name");
    table.addColumn(addressColumn, "Address");

    // Set the total row count. You might send an RPC request to determine the
    // total row count.
    table.setRowCount(CONTACTS.size(), true);

    // Set the range to display. In this case, our visible range is smaller than
    // the data set.
    table.setVisibleRange(0, 3);

    // Create a data provider.
    AsyncDataProvider<Contact> dataProvider = new AsyncDataProvider<Contact>() {
      @Override
      protected void onRangeChanged(HasData<Contact> display) {
        final Range range = display.getVisibleRange();

        // Get the ColumnSortInfo from the table.
        final ColumnSortList sortList = table.getColumnSortList();

        // This timer is here to illustrate the asynchronous nature of this data
        // provider. In practice, you would use an asynchronous RPC call to
        // request data in the specified range.
        new Timer() {
          @Override
          public void run() {
            int start = range.getStart();
            int end = start + range.getLength();
            // This sorting code is here so the example works. In practice, you
            // would sort on the server.
            Collections.sort(CONTACTS, new Comparator<Tester.Contact>() {
              public int compare(Contact o1, Contact o2) {
                if (o1 == o2) {
                  return 0;
                }

                // Compare the name columns.
                int diff = -1;
                if (o1 != null) {
                  diff = (o2 != null) ? o1.name.compareTo(o2.name) : 1;
                }
                return sortList.get(0).isAscending() ? diff : -diff;
              }
            });
            List<Contact> dataInRange = CONTACTS.subList(start, end);

            // Push the data back into the list.
            table.setRowData(start, dataInRange);
          }
        }.schedule(2000);
      }
    };

    // Connect the list to the data provider.
    dataProvider.addDataDisplay(table);

    // Add a ColumnSortEvent.AsyncHandler to connect sorting to the
    // AsyncDataPRrovider.
    AsyncHandler columnSortHandler = new AsyncHandler(table);
    table.addColumnSortHandler(columnSortHandler);

    // We know that the data is sorted alphabetically by default.
    table.getColumnSortList().push(nameColumn);

    // Add it to the root panel.
    RootPanel.get().add(table);
  }
}

控制列宽

默认情况下,单元格表格中的列会扩展以适应单元格内容的宽度。对于静态表格来说这很好用,但如果由于分页或用户交互导致内容发生变化,列的宽度可能会发生变化,从而导致表格看起来跳跃。单元格表格提供了一个 API,使您能够对可用宽度如何分配到各列之间进行细粒度控制。

为了对列的宽度进行细粒度控制,您必须通过将 true 传递给 CellTable.setWidth(String, boolean) 将表格布局设置为“固定”。在固定宽度模式下,表格的行为与正常情况不同。以下部分描述了实现各种效果的方案。

代码示例 - 下面的示例创建了一个具有固定宽度列的单元格表格,这些列会扩展以填充可用空间。

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Tester implements EntryPoint {
  // A simple data type that represents a contact.
  private static class Contact {
    private final String address;
    private final String name;

    public Contact(String name, String address) {
      this.name = name;
      this.address = address;
    }
  }

  // The list of data to display.
  private static List<Contact> CONTACTS = Arrays.asList(new Contact("John",
      "123 Fourth Road"), new Contact("Mary", "222 Lancer Lane"));

  public void onModuleLoad() {

    // Create a CellTable.
    CellTable<Contact> table = new CellTable<Contact>();

    // Create name column.
    TextColumn<Contact> nameColumn = new TextColumn<Contact>() {
      @Override
      public String getValue(Contact contact) {
        return contact.name;
      }
    };

    // Create address column.
    TextColumn<Contact> addressColumn = new TextColumn<Contact>() {
      @Override
      public String getValue(Contact contact) {
        return contact.address;
      }
    };

    // Add the columns.
    table.addColumn(nameColumn, "Name");
    table.addColumn(addressColumn, "Address");

    // Set the width of the table and put the table in fixed width mode.
    table.setWidth("100%", true);

    // Set the width of each column.
    table.setColumnWidth(nameColumn, 35.0, Unit.PCT);
    table.setColumnWidth(addressColumn, 65.0, Unit.PCT);

    // Set the total row count. This isn't strictly necessary, but it affects
    // paging calculations, so its good habit to keep the row count up to date.
    table.setRowCount(CONTACTS.size(), true);

    // Push the data into the widget.
    table.setRowData(0, CONTACTS);

    // Add it to the root panel.
    RootPanel.get().add(table);
  }
}

指定所有列的精确宽度

如果您想为每列分配一个特定的宽度,那么您必须将表格宽度设置为“auto”,并为每列分配一个绝对宽度。

警告:如果您将表格的宽度设置为“auto”,并且没有设置列的宽度,那么该列将不可见。列的默认宽度为 0。

table.setWidth("auto", true);
    table.setColumnWidth(col0, 100.0, Unit.PX);
    table.setColumnWidth(col1, 150.0, Unit.PX);
    table.setColumnWidth(col2, 250.0, Unit.PX);
    table.setColumnWidth(col3, 100.0, Unit.PX);

指定所有列的相对宽度

您可以通过将表格的宽度设置为非零值(例如“100%”或“600px”)并将每列的宽度设置为百分比来为每列分配相对宽度。

警告:每当您使用百分比设置一个或多个列的宽度时,这些百分比应该加起来为 100%。如果未能做到这一点,可能会导致意想不到的布局问题。

table.setWidth("100%", true);
    table.setColumnWidth(col0, 10.0, Unit.PCT);
    table.setColumnWidth(col1, 25.0, Unit.PCT);
    table.setColumnWidth(col2, 25.0, Unit.PCT);
    table.setColumnWidth(col3, 40.0, Unit.PCT);

混合使用固定宽度和相对宽度列

固定宽度表格的一大特点是,您可以指定某些列应该具有固定宽度,而其他列应该根据表格的宽度进行调整大小。例如,您可能希望固定复选框列的宽度,因为复选框始终大约为 25px 宽,但让其他列进行调整大小。

为了实现这种效果,请将表格的宽度设置为非零值,使用非相对单位(例如 px、em 或 ex)设置固定列的宽度,并将剩余列的宽度设置为百分比。如果您只希望一列可调整大小,那么将其宽度设置为 100%,并将所有其他列的宽度设置为像素。

警告:以百分比指定的列的宽度应该加起来为 100%。如果它们没有加起来,那么以像素指定的列也会以不可预测的方式随着表格进行调整大小。

table.setWidth("100%", true);
    table.setColumnWidth(checkboxCol, 10.0, Unit.PX);
    table.setColumnWidth(nameCol, 35.0, Unit.PCT);
    table.setColumnWidth(descriptionCol, 65.0, Unit.PCT);