Paging
Paging是GXT提供的非常有用的功能。顾名思义,就是分页显示数据,而不是一页显示所有的数据。GXT支持远程和本地的分页:远程分页就是真分页,每次server端返回数据都是数据库里分页后的数据;本地的分页就是假分页,数据库一次性load全部数据后,前端再分页内存里面的数据。为了方便起见,仅仅使用假分页,给大家展示一下Paging的功能。
介绍一下分页工作的相关类
PagingLoadResult
分页的数据,其必须被填充到PagingLoadResult。PagingLoadResult是ListLoadResult的扩展接口,提供了额外的功能(TotalLength和Offset),
PagingLoadConfig
PagingLoadConfig封装了请求分页数据的参数,指定了offset,数据返回起始点等。
接下来,我们要在RSSReader项目里,新建一个方法,返回PagingLoadResult<Item>
- FeedService接口里,定义第二个loadItems方法,
PagingLoadResult<Item> loadItems(String feedUrl, final
PagingLoadConfig config);
- FeedServiceAsync接口里,定义其回调方法
void loadItems(String feedUrl, PagingLoadConfig config,
AsyncCallback<PagingLoadResult<Item>> callback);
- FeedServiceImpl里,实现这个抽象方法。
@Override
public PagingLoadResult<Item> loadItems(String feedUrl,
PagingLoadConfig config) {
List<Item> items = loadItems(feedUrl);
return getPagingLoadResult(items, config);
}
- getPagingLoadResult的方法实现如下:
private PagingLoadResult<Item> getPagingLoadResult(List<Item> items,
PagingLoadConfig config) {
//定义pageItems,存储Item,作为返回的数据源
List<Item> pageItems = new ArrayList<Item>();
//通过PagingLoadConfig,获得相关参数(offset)
int offset = config.getOffset();
//获得全部数据大小
int limit = items.size();
//根据offset获得limit
if (config.getLimit() > 0) {
limit = Math.min(offset + config.getLimit(), limit);
}
//定义好边界之后,开始读取数据
for (int i = offset; i < limit; i++) {
pageItems.add(items.get(i));
}
//通过pageItems,转化成BasePagingLoadResult,同时赋值上offset和totalLength
return new BasePagingLoadResult<Item>(pageItems, offset, items.size());
}
PagingModelMemoryProxy
对于返回分页的数据的方法的代理proxy需要使用PagingModelMemoryProxy,针对于PagingModelMemoryProxy的loader是PagingLoaderPagingLoader
PagingLoader的构造函数里,参数指明了类型是PagingModelMemoryProxy,PagingLoader会通过PagingModelMemoryProxy,load分页的数据集到store里。
PagingLoader<PagingLoadResult<ModelData>> loader = new BasePagingLoader<PagingLoadResult<ModelData>>(proxy);
对于load数据的时候,需要指定offset和pageSize
loader.load(0, 4);//public void load(int offset, int pageSize);
对于其过程使用的store是ListStore,因为数据本身来说,就是一般的list数据集,分页的操作只是从大的list数据集里面获取部分数据集。
PagingToolBar
PagingToolBar extends ToolBar,预定义了相关的分页功能。
对于PagingToolBar来说,他数据源所绑定的是PagingLoader,大致代码如下:
toolBar.bind(loader);
add(toolBar);
接下来,我们要在RSSReader项目里实现上面提到的所有概念。
- 新建ItemPagingGrid类,整个代码内容如下:
package com.danielvaughan.rssreader.client.grids;
import java.util.ArrayList;
import java.util.List;
import com.danielvaughan.rssreader.client.RSSReaderConstants;
import com.danielvaughan.rssreader.client.services.FeedServiceAsync;
import com.danielvaughan.rssreader.shared.model.Item;
import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.data.BasePagingLoader;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.PagingLoadConfig;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoader;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;
public class ItemPagingGrid extends LayoutContainer {
private static final int PAGE_SIZE = 2;
public ItemPagingGrid() {
setLayout(new FitLayout());
}
@Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
// ColumnModel
final List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
GridCellRenderer<ModelData> itemsRenderer = new GridCellRenderer<ModelData>() {
@Override
public Object render(ModelData model, String property,
ColumnData config, int rowIndex, int colIndex,
ListStore<ModelData> store, Grid<ModelData> grid) {
String title = model.get("title");
String description = model.get("description");
return "<b>" + title + "</b><br/>" + description;
}
};
ColumnConfig column = new ColumnConfig();
column.setId("items");
column.setRenderer(itemsRenderer);
column.setHeader("Items");
columns.add(column);
final ColumnModel columnModel = new ColumnModel(columns);
// Proxy:
final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml";
final FeedServiceAsync feedService = Registry
.get(RSSReaderConstants.FEED_SERVICE);
RpcProxy<PagingLoadResult<Item>> proxy = new RpcProxy<PagingLoadResult<Item>>() {
@Override
protected void load(Object loadConfig,// loadConfig是GXT内部自动传入的
AsyncCallback<PagingLoadResult<Item>> callback) {
feedService.loadItems(TEST_DATA_FILE,
(PagingLoadConfig) loadConfig, callback);
}
};
// Loader:根据proxy,生成loader,因为返回的类型正好是PagingLoadResult,不需要数据转换
PagingLoader<PagingLoadResult<Item>> loader = new BasePagingLoader<PagingLoadResult<Item>>(
proxy);
// Store:
ListStore<ModelData> itemStore = new ListStore<ModelData>(loader);
// PagingToolBar:定义的时候需要传入分页大小
final PagingToolBar toolBar = new PagingToolBar(PAGE_SIZE);
toolBar.bind(loader);
// Grid:定义的时候,需要传入store和columnModel
Grid<ModelData> grid = new Grid<ModelData>(itemStore, columnModel);
grid.setBorders(true);
grid.setAutoExpandColumn("items");
loader.load();//此时的load应用了默认的PagingLoadConfig
// Grid不直接加入到LayoutContainer,而是Grid添加到ContentPanel,ContentPanel添加到LayoutContainer
ContentPanel panel = new ContentPanel();
panel.setLayout(new FitLayout());
panel.add(grid);
panel.setHeaderVisible(false);
panel.setBottomComponent(toolBar);
add(panel);
}
}
- 最后把ItemPagingGrid添加到RssMainPanel里,显示出来。注释掉之前的components
package com.danielvaughan.rssreader.client.components;
import com.danielvaughan.rssreader.client.grids.ItemPagingGrid;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
public class RssMainPanel extends ContentPanel {
public RssMainPanel() {
setHeading("Main");
setLayout(new FitLayout());
// add(new ItemGrid());
// add(new ItemCategoryGrid());
add(new ItemPagingGrid());
}
}
- 运行结果如下
- 如果想让Grid在加载数据的时候直接到第二页。可以使用:loader.load(2, PAGE_SIZE);
- 只要绑定了(toolBar.bind(loader);)loader之后,其翻页操作不需要我们实现,PagingToolBar内部已经实现好了。