UiCellTable
单元格表格(数据展示表格)提供高性能渲染,以表格视图展示大型数据集。您可以查看 GWT 展示中的 单元格表格示例 来了解其工作原理。
本开发者指南将带您了解特定于单元格表格的一些高级功能,例如列排序。如果您不熟悉单元格小部件,请在继续之前阅读 单元格小部件开发者指南。
列排序
单元格表格内置了对列排序的支持。使用 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);