0
点赞
收藏
分享

微信扫一扫

GXT之旅:第五章:高级Components(1)——Trees和TreeGrid(2)


TreeGrid

TreeGrid将Trees和Grids的功能结合在一起。整体上看是由多个columns组成的Grid,但是内容上看,支持显示树目录结构的数据。

他和TreePanel一样,使用的Store也是TreeStore,ModelDate也是BaseTreeModel。


TreeGridCellRenderer

TreeGridCellRenderer实现了GridCellRenderer,其功能顾名思义,用来渲染TreeGrid的column的。接下来我们要在RSSReader项目里使用TreeGridCellRenderer,对于一个renderer来说可以被设置在任何一个column上。

  • 在package:com.danielvaughan.rssreader.client.grids里,新建ItemCategoryGrid,继承LayoutContainer

public class ItemCategoryGrid extends LayoutContainer {
public ItemCategoryGrid() {
setLayout(new FitLayout());
}
}

  • Override onRender方法,在其方法内从Registry内获得FeedService

protected void onRender(Element parent, int index) {
super.onRender(parent, index);
final FeedServiceAsync feedService = (FeedServiceAsync) Registry
.get(RSSReaderConstants.FEED_SERVICE);
}

  • 通过RpcProxy,调用FeedService.loadCategorisedItems方法。因为对于Trees或者TreeGrid的数据,每次数据加载都只加载当前node节点的children,不是一股脑的将所有数据都加载到client。所以每次的请求调用过程,就都需要传入参数——loadConfig,那么对于当前的例子来说,loadConfig就是Category(BaseTreeModel)。

final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml";
RpcProxy<List<ModelData>> proxy = new RpcProxy<List<ModelData>>() {
@Override
protected void load(Object loadConfig,
AsyncCallback<List<ModelData>> callback) {
feedService.loadCategorisedItems(TEST_DATA_FILE,
(Category) loadConfig, callback);
}
};

  • 新建BaseTreeLoader对象,override hasChildren方法。

final TreeLoader<ModelData> loader = new BaseTreeLoader<ModelData>(
proxy) {
@Override
public boolean hasChildren(ModelData parent) {
if (parent instanceof Category) {
return true;
} else {
return false;
}
}
};

  • 这里不需要使用reader,因为RpcProxy所调用的远程方法,已经返回的是ModelData。通过刚刚生成的loader,传入TreeStore的构造函数。

final TreeStore<ModelData> feedStore = new TreeStore<ModelData>(loader);


  • 创建ColumnConfig,使用TreeGridCellRenderer作为Tree的渲染器

ColumnConfig title = new ColumnConfig("title", "Title", 200);
title.setRenderer(new TreeGridCellRenderer<ModelData>());

  • 新建另外一个ColumnConfig description,然后将ColumnConfig title和description以list的形式传入ColumnModel

ColumnConfig description = new ColumnConfig("description","Description", 200);
ColumnModel columnModel = new ColumnModel(Arrays.asList(title,description));

  • 定义TreeGrid,传入刚刚生成feedStore和columnModel。让title列自动伸展,再设置上一节定义的ICONs

TreeGrid<ModelData> treeGrid = new TreeGrid<ModelData>(feedStore,columnModel);
treeGrid.setBorders(true);
treeGrid.setAutoExpandColumn("title");
treeGrid.getStyle().setLeafIcon(Resources.ICONS.rss());

  • 通过loader的load方法,开始启动整个执行过程,将treeGrid加入LayoutContainer

loader.load();
add(treeGrid);

  • 在RssMainPanel类的构造函数里,去掉先前add的ItemGrid,替换为add ItemCategoryGrid.

public RssMainPanel() {
setHeading("Main");
setLayout(new FitLayout());
add(new ItemCategoryGrid());
}

  • 最后运行程序如下:


  • 整个代码如下:

package com.danielvaughan.rssreader.client.grids;

import java.util.Arrays;
import java.util.List;

import com.danielvaughan.rssreader.client.RSSReaderConstants;
import com.danielvaughan.rssreader.client.resources.Resources;
import com.danielvaughan.rssreader.client.services.FeedServiceAsync;
import com.danielvaughan.rssreader.shared.model.Category;
import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.data.BaseTreeLoader;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.data.TreeLoader;
import com.extjs.gxt.ui.client.store.TreeStore;
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.ColumnModel;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.treegrid.TreeGrid;
import com.extjs.gxt.ui.client.widget.treegrid.TreeGridCellRenderer;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class ItemCategoryGrid extends LayoutContainer {
public ItemCategoryGrid() {
setLayout(new FitLayout());
}

@Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
final FeedServiceAsync feedService = (FeedServiceAsync) Registry
.get(RSSReaderConstants.FEED_SERVICE);
final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml";
RpcProxy<List<ModelData>> proxy = new RpcProxy<List<ModelData>>() {
@Override
protected void load(Object loadConfig,
AsyncCallback<List<ModelData>> callback) {
feedService.loadCategorisedItems(TEST_DATA_FILE,
(Category) loadConfig, callback);
}
};

final TreeLoader<ModelData> loader = new BaseTreeLoader<ModelData>(
proxy) {
@Override
public boolean hasChildren(ModelData parent) {
if (parent instanceof Category) {
return true;
} else {
return false;
}
}
};

final TreeStore<ModelData> feedStore = new TreeStore<ModelData>(loader);

ColumnConfig title = new ColumnConfig("title", "Title", 200);
ColumnConfig description = new ColumnConfig("description","Description", 200);

title.setRenderer(new TreeGridCellRenderer<ModelData>());

ColumnModel columnModel = new ColumnModel(Arrays.asList(title,description));

TreeGrid<ModelData> treeGrid = new TreeGrid<ModelData>(feedStore,
columnModel);
treeGrid.setBorders(true);
treeGrid.setAutoExpandColumn("title");
treeGrid.getStyle().setLeafIcon(Resources.ICONS.rss());
//loader.load();//不需要load
add(treeGrid);//当treeGrid添加之后,GXT内部会自动的loader.load();,如果我们再手动的load的话,就会call service 两次
}
}



注意:通过断点跟踪FeedServiceImpl.loadCategorisedItems方法。我们会发现,此方法会被多次调用。整个现象如下:

  • TreeGrid在初始化的时候(也就是load的时候),会调用一次FeedServiceImpl.loadCategorisedItems方法。数据显示的时候,文件夹图标都是闭合的。
  • 当闭合的图标第一次被打开的时候,会在调用一次FeedServiceImpl.loadCategorisedItems方法。此时,代码内部会自动的将当前节点的Category,传入到proxy的load方法中去,作为参数,让FeedServiceImpl.loadCategorisedItems方法去根据Category,获得items数据。
  • 当闭合的图标关闭后再打开的时候,就不会调用了。也就是说,第一次将内容加载到client之后,就不会再发出请求了。

大家再看看源代码——TreeGridCellRenderer.render方法。

  • 当我们在新建TreeGridCellRenderer的时候,不需要override render方法,GXT已经给写好了。直接new出对象既可。
  • TreeGrid在初始化的时候(也就是load的时候),有多少条数据,就会调用多少遍TreeGridCellRenderer.render方法。
  • 当点击文件夹图标的节点的时候,也就会自动的调用TreeGridCellRenderer.render方法。


举报

相关推荐

0 条评论