您的位置:首页 > 其它

基于SmartGwt的分页组件

2011-07-26 17:47 267 查看
最近发现oschina不给我发每周精彩回顾了,才想起距离上次写东西已经有9个月了,于是狠狠的惭愧了一把。程序员光干活,不总结是不行的,于是便跟大家分享下下面这些开发体验。

最近公司的外网项目,都准备用Gwt开发,经过之前的一些试验,公司决定采用SmartGwt 2.4作为前台框架。经过一段使用之后,感觉SmartGwt基本上比较容易上手。不过,虽然他的showcase的例子挺丰富,但只覆盖了很少的api,所以基本上还是天天翻着api来开发。

其组件库涵盖了绝大多数常见的控件,但是没有分页条,居然少了这么常用的组件,着实让人遗憾。先google了一下,没有令人满意的现成的扩展组件,查了半天,只在一个英文论坛里,发现一个半成品,只是个实现了部分页面展示逻辑的页面组件,而且没有数据交互。无奈,找不到现成的,只能自己动手丰衣足食了。

一、定义分页条功能

功能至少要满足基本需要。
比如对于用户来说,页面功能应该包括:
1、能够定位数据到:首页,上一页,下一页,末页
2、能够展示当前页和总页数
3、直接跳转到指定页(大于零,小于总页数)
4、根据当前页和总页数,控制按钮可用状态
对于程序员来说,这个组件应该可以:
1、方便的初始化工具条组件并能绑定数据展示组件(比如grid)
2、定制每页记录数
3、最好和数据查询方法分离,消除对业务查询方法的依赖
4、最好能有个模态遮罩,在数据加载过程中,给予提示,同时限制用户的重复操作。

二、代码实现

经过分析和简单的设计,决定通过两个类来实现:

1、一个纯页面组件,继承自com.smartgwt.client.widgets.toolbar.ToolStrip。代码实现思路就不写了,反正是从混沌到清晰的一个过程。直接帖代码了

import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.toolbar.ToolStrip;

/**
*
* 分页工具条
*
* 使用方法:
* 1、实例化一个分页工具栏,传入每页记录条数和绑定的grid
* 2、实现一个ListGridDataControl(实例化方法参见类中注释,注意和分页工具的相互调用),并把它设值给分页工具栏的dataControl属性,
*    注意:分页工具条和ListGridDataControl需要紧密配合相互调用。
* 3、调用active()方法,激活分页条并加载grid数据
*
* 提示:
* 1、本分页工具不处理grid的行号,行号理解为grid的列定义范畴
* 2、可以多次调用active()方法,调用的结果相当于把分页栏定位到首页,并重新获取总页数
* 3、如果查询业务数据的参数改变时,可以重新实现并设置ListGridDataControl,然后调用active()
* 4、可以调用setMaskMessage()设置遮罩的提示信息,如果不设置,采用默认值
*
* 说明:
* 之所以需要ListGridDataControl回调分页工具条的方法,导致增加了相互依赖,主要是考虑到获取数据和获取记录总数的方法通常是异步的,
* 为保持操作的同步性,只能通过互相调用的方式保持工具条和grid的正常工作。
*
* @author weichao
* @version 1.0
*/
public class GridPaginationBar extends ToolStrip{

/**
* 模态遮罩
*/
ModalWindow mask;

private String maskMessage = " 数据加载中...... ";

public void setMaskMessage(String maskMessage) {
this.maskMessage = maskMessage;
}
/**
* 每页条数
*/
private int pageSize = -1;

/**
* 当前页
*/
private int pageNum = -1;

/**
* 总页数
*/
private int totalPage = -1;

/**
* 数据记录条数
*/
private int totalRowNum = -1;

/**
* 绑定的grid
*/
private final ListGrid grid;

//首页  TopImgButton first = new TopImgButton(16,16,"/img/control_start_blue.png","/img/control_start.png");

//上一页
TopImgButton backward = new TopImgButton(16,16,"/img/control_rewind_blue.png","/img/control_rewind.png");

//下一页
TopImgButton forward = new TopImgButton(16,16,"/img/control_fastforward_blue.png","/img/control_fastforward.png");

//末页
TopImgButton last = new TopImgButton(16,16,"/img/control_end_blue.png","/img/control_end.png");

//输入框form
DynamicForm pageForm;

//页码输入框
protected TextItem pageText;

//转到按钮
IButton go = new IButton("转到");

//总页数
protected Label totalLabel;

//grid数据控制器
private ListGridDataControl dataControl;

public void setDataControl(ListGridDataControl dataControl){
this.dataControl = dataControl;
}

public GridPaginationBar(ListGrid listGrid, int pageSize) {
this(listGrid, pageSize,null);
}

/**
*
* 构造方法中,只初始化工具条元素和事件,不初始化数据,
* 构造完成后工具条处于禁用状态,需要首先传入grid数据控制器,
* 然后调用active()方法来激活工具条,并开始加载数据。
*
* @param listGrid 绑定的grid
* @param pageSize 每页记录条数
* @param maskCanvas 加载数据过程中,需要用遮罩遮盖的控件,如果传入null,则默认遮盖的对象为绑定的grid
*/
public GridPaginationBar(ListGrid listGrid, int pageSize, Canvas maskCanvas) {
this.grid = listGrid;
mask = new ModalWindow(maskCanvas == null ? grid : maskCanvas);
mask.setLoadingIcon("/img/loading.gif");
this.pageSize = pageSize;
first.setButtonTip("首页");
first.setButtonClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
goToPage(1);
}
});
backward.setButtonTip("上一页");
backward.setButtonClickHandler(new ClickHandler(){
public void onClick(ClickEvent event){
goToPage(pageNum - 1);
}
});
pageText = new TextItem();
pageText.setWidth(40);
pageText.setHeight(20);
pageText.setShowTitle(false);
pageText.setTextAlign(Alignment.RIGHT);
go.setWidth(34);
go.setHeight(20);
go.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
String page = pageText.getValueAsString();
if(page == null || page.trim().equals("")){
SC.say("请输入页码");
return ;
}else {
try{
int pageint = Integer.valueOf(page);
if(pageint<1){
SC.say("输入的页码不能小于1");
return;
}else if(pageint>totalPage){
SC.say("输入的页码不能大于总页数 "+totalPage);
return;
}else {
goToPage(pageint);
}
}catch(NumberFormatException e){
SC.say("请输入整数");
return;
}
}
}});

forward.setButtonTip("下一页");
forward.setButtonClickHandler(new ClickHandler(){
public void onClick(ClickEvent event){
goToPage(pageNum + 1);
}
});

last.setButtonTip("末页");
last.setButtonClickHandler(new ClickHandler(){
public void onClick(ClickEvent event){
goToPage(totalPage);
}
});

totalLabel = new Label();
totalLabel.setWrap(false);
totalLabel.setWidth(50);

setHeight(20);
setOverflow(Overflow.VISIBLE);
setStyleName("normal");
this.setMargin(5);

pageForm = new DynamicForm();
pageForm.setNumCols(1);
pageForm.setWidth(45);
pageForm.setItems(pageText);
Label blank1 = new Label();
blank1.setContents(" ");
blank1.setWidth(5);
blank1.setHeight(20);

Label blank2 = new Label();
blank2.setContents(" ");
blank2.setWidth(5);
blank2.setHeight(20);

Label blank3 = new Label();
blank3.setContents(" ");
blank3.setWidth(15);
blank3.setHeight(20);

Label blank4 = new Label();
blank4.setContents(" ");
blank4.setWidth(5);
blank4.setHeight(20);

Label blank5 = new Label();
blank5.setContents(" ");
blank5.setWidth(5);
blank5.setHeight(20);

addMember(first);
addMember(blank1);
addMember(backward);
addMember(blank2);
addMember(pageForm);
addMember(go);
addMember(blank5);
addMember(forward);
addMember(blank4);
addMember(last);
addMember(blank3);
addMember(totalLabel);
setAlign(Alignment.RIGHT);
resetPaginationState();
}

/**
* 转到指定页,获取分页数据并装载,
* 获取数据过程中,加模态遮罩
*
* @param pageNum
*/
public void goToPage(int pageNum) {
go.disable();
if (pageNum > totalPage)
pageNum = totalPage;
if (pageNum < 1)
pageNum = 1;
if (pageNum == this.pageNum) {
go.enable();
return;
}
mask.show(maskMessage, true);
//fetch data and reload grid
this.pageNum = pageNum;
int startNum = (pageNum - 1) * pageSize;
dataControl.fetchData(startNum, pageSize);
}

/**
* 根据记录总数计算总页数
*/
private void countTotalPages()
{
if(totalRowNum < 1){
totalPage = -1;
return;
}
int pages = (int) Math.ceil(((float) totalRowNum) / ((float) pageSize));
// never return zero pages
if (pages == 0)
pages = 1;
this.totalPage=pages;
pageNum = 1;
}

/**
* 首次查询数据,获取数据总数等信息,并更新分页条状态
* 获取数据过程中,加模态遮罩
*/
public void active(){
if(dataControl == null){
SC.say("错误","分页栏未配置ListGridDataControl数据控制器,请检查代码");
return;
}
//首先禁用工具条
if(pageNum != -1){
resetPaginationState();
}
mask.show(maskMessage, true);
dataControl.getTotal();
}

/**
* ListGridDataControl获取总记录数后的回调方法
* @param all
*/
public void afterGetTotal(int all){
this.totalRowNum = all;
countTotalPages();
if(totalPage==-1){
//如果没有查询到数据,则清空原来的数据
afterFetchData(new ListGridRecord[0]);
} else {
dataControl.fetchData(0, pageSize);
}
}

/**
* ListGridDataControl获取数据后的回调方法
* @param datas
*/
public void afterFetchData(ListGridRecord[] datas){
if(datas != null){
dataControl.loadData(datas);
}
updatePageinationState();
mask.hide();
}

/**
* 清除分页工具条状态,全部置灰,不负责清空grid当前数据
*/
private void resetPaginationState(){
pageNum = -1;
totalPage = -1;
totalRowNum = -1;
first.disable();
backward.disable();
last.disable();
forward.disable();
pageText.disable();
go.disable();
totalLabel.setContents("");
}

/**
* 依据当前页和总页数控制工具条状态
* 规则:
*      当前页为-1,则说明工具条尚未激活或者没有查询到数据,不需要处理;
*      当前页等于1,则首页按钮和上一页按钮置灰,否则,激活;
*      当前页等于总页数,则末页按钮和上一页按钮置灰,否则,激活;
*/
private void updatePageinationState() {
if(pageNum==-1||totalPage==-1){
return;
}
totalLabel.setContents("第" + pageNum + "页/共" + totalPage + "页");
pageText.enable();
go.enable();
pageText.setValue(pageNum);
if (pageNum == 1){
first.disable();
backward.disable();
} else {
first.enable();
backward.enable();
}
if (pageNum == totalPage){
last.disable();
forward.disable();
} else {
last.enable();
forward.enable();
}
}
}


2、一个控制接口类
即GridPaginationBar 类里的ListGridDataControl ,代码如下:

import com.smartgwt.client.widgets.grid.ListGridRecord;

/**
*
* @author weichao
* listGrid数据获取及装载接口 ,和工具条有紧密的相互调用
* grid加分页工具条时,需要实现此接口并提供给分页工具条
*
*
* 示例:
*
* GridPaginationBar pageBar = new GridPaginationBar(bizGrid,20,bizGrid.getParentElement());
*
* pageBar.setDataControl(new ListGridDataControl(){
*          public void fetchData(int start, int pageSize) {
*              service.getBusiness(sid,start,pageSize,
*                      new AsyncCallback<List<XXXXXVO>>() {
*                          public void onFailure(Throwable caught) {
*                              Window.alert(caught.getMessage());
*                          }
*                          public void onSuccess(List<XXXXXVO> result) {
*                              list = result;
*                              pageBar.afterFetchData(RenderBizData.getNewRecords(result));
*                          }
*                      });
*          }
*          public void getTotal() {
*              service.getBusinessTotal(sid, new AsyncCallback<Integer>(){
*                  public void onFailure(Throwable arg0) {
*                      Window.alert(arg0.getMessage());
*                  }
*                  public void onSuccess(Integer arg0) {
*                      pageBar.afterGetTotal(arg0);
*                  }} );
*          }
*          public void loadData(ListGridRecord[] records) {
*               bizGrid.setData(records);
*          }});
*/
public interface ListGridDataControl {

/**
* 获取分页数据,并回调分页工具栏的afterFetchData()方法,
* 如果需要异步获取数据,请注意回调afterFetchData()的时机,保持数据的同步操作。
*
* @param start
* @param pageSize
*/
public void fetchData(int start,int pageSize);

/**
* 获取数据记录总数,并回调分页工具栏的afterGetTotal()方法
* 如果需要异步获取数据,请注意回调afterGetTotal()的时机,保持数据的同步操作。
*
* @return 总数
*/
public void getTotal();

/**
* 把数据装载入grid
* @param records
*/
public void loadData(ListGridRecord[] records);
}


3、从网上找了个模态窗口ModalWindow ,直接使用了,这里就不贴代码了:
需要的可以从这里找
http://code.google.com/p/smartgwt-extensions/source/browse/trunk/mainprojects/src/main/java/com/smartgwt/extensions#extensions%2Fmodal%2Fclient%253Fstate%253Dclosed

4、TopImgButton类是自己实现的一个按钮类,当然你可以用smartgwt的按钮 ,或者你自己写个。

import com.smartgwt.client.types.Cursor;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;

/**
* @author weichao
* 有激活和置灰两种状态的图片按钮
*/
public class TopImgButton extends HLayout{
Img enable = new Img();
Img disable = new Img();
private boolean _enable = true;
public TopImgButton(int buttonWidth,int buttonHeight,String enableImgSrc,String disableImgSrc){
setWidth(buttonWidth);
setHeight(buttonHeight);
enable.setSrc(enableImgSrc);
enable.setWidth(buttonWidth);
enable.setHeight(buttonHeight);
enable.setCursor(Cursor.POINTER);
disable.setSrc(disableImgSrc);
disable.setWidth(buttonWidth);
disable.setHeight(buttonHeight);
addMember(enable);
}

public void enable(){
if(!_enable){
removeMember(disable);
addMember(enable);
_enable = !_enable;
}
}

public void disable(){
if(_enable){
removeMember(enable);
addMember(disable);
_enable = !_enable;
}
}

public void setButtonClickHandler(ClickHandler handler){
enable.addClickHandler(handler);
}

public void setButtonTip(String tipMessage){
enable.setTooltip(tipMessage);
}
}


三、效果

注释里写的比较多了,还有示例也帖在类的注释里了,所以就不再解释怎么用了。
经过几番测试,感觉运行比较稳定。希望能对需要smartgwt分页的朋友有所帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: