示例效果图
示例源码
这里以菜单为例,来展示 TreePanel 的使用。
TreeExample
package fan.tutorial.client.ui.tree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.extjs.gxt.ui.client.data.HttpProxy;
import com.extjs.gxt.ui.client.data.JsonReader;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.ModelType;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.layout.AccordionLayout;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanel;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.user.client.rpc.AsyncCallback;
import fan.tutorial.client.commons.TreeNodeUtil;
import fan.tutorial.client.model.ITreeNode;
import fan.tutorial.client.model.TreeNode;
import fan.tutorial.client.model.TreeNode.NodeType;
import fan.tutorial.server.value.Constant;
public class TreeExample extends ContentPanel {
public TreeExample() {
//设置面板标题
setHeadingHtml("Tree Example");
//设置面板宽度高度
setSize(250, 400);
//设置面板布局
setLayout(new AccordionLayout());
//创建ModelType
ModelType modelType = new ModelType();
//设置根名称(与json数据根名称要保持一致, 否则无法正确的解析数据)
modelType.setRoot(Constant.RESULT);
//添加需要使用到的字段域, 未被添加的字段域无法使用
modelType.addField(ITreeNode.ID);
modelType.addField(ITreeNode.TEXT);
modelType.addField(ITreeNode.NODE_TYPE);
modelType.addField(ITreeNode.PRIOR_LEVEL);
modelType.addField(ITreeNode.PARENT_NODE_ID);
//Spring MVC Controller 请求地址
String url = GWT.getHostPageBaseURL() + "menu/treenodes.json";
//构建RequestBuilder
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
//创建HttpProxy
HttpProxy<List<ModelData>> proxy = new HttpProxy<List<ModelData>>(builder);
//JsonReader
JsonReader<List<ModelData>> reader = new JsonReader<List<ModelData>>(modelType);
//加载数据
proxy.load(reader, null, new AsyncCallback<List<ModelData>>() {
public void onSuccess(List<ModelData> result) {
//树节点
List<TreeNode> treeNodes = TreeNodeUtil.modelDatas2TreeNodes(result);
//面板类节点
List<TreeNode> panels = new ArrayList<TreeNode>();
//根类节点
List<TreeNode> roots = new ArrayList<TreeNode>();
//叶子类节点
List<TreeNode> leafs = new ArrayList<TreeNode>();
for(TreeNode node : treeNodes){
if(node.getNodeType().ordinal() == NodeType.PANEL.ordinal()){
panels.add(node);
}else if(node.getNodeType().ordinal() == NodeType.ROOT.ordinal()){
roots.add(node);
}else{
leafs.add(node);
}
}
//排序面板类节点
Collections.sort(panels);
//渲染树节点
onRender(panels, roots, leafs);
//渲染完成之后重新渲染面板内容
layout(true);
}
public void onFailure(Throwable caught) {
}
});
}
//渲染树节点
private void onRender(List<TreeNode> panels, List<TreeNode> roots, List<TreeNode> leafs){
for(TreeNode panelNode : panels){
//面板类节点面板
ContentPanel panel = new ContentPanel();
//设置面板类节点标题
panel.setHeadingHtml(panelNode.getText());
TreeStore<ModelData> store = new TreeStore<ModelData>();
TreePanel<ModelData> tree = new TreePanel<ModelData>(store);
//树结构内容显示文本
tree.setDisplayProperty(ITreeNode.TEXT);
//面板类节点的孩子节点(根类节点)
List<TreeNode> panelNodeChildren = hasChildrenNode(panelNode, roots);
if(panelNodeChildren.size() > 0){
//迭代根类节点
for(TreeNode root : panelNodeChildren){
//根类节点的孩子节点(叶子节点)
List<TreeNode> rootNodeChildren = hasChildrenNode(root, leafs);
ModelData modelData = TreeNodeUtil.treeNode2ModelData(root);
if(rootNodeChildren.size() > 0){
//添加根类节点
store.add(modelData, true);
//迭代叶子节点
for(TreeNode leaf : rootNodeChildren){
ModelData m = TreeNodeUtil.treeNode2ModelData(leaf);
//添加叶子节点
store.add(modelData, m, false);
}
}else{
//添加根类节点
store.add(modelData, false);
}
//展开节点
tree.setExpanded(modelData, true);
}
}
//为面板节点添加树节点
panel.add(tree);
//添加面板节点到容器
add(panel);
}
}
//判断节点是否拥有孩子节点
private List<TreeNode> hasChildrenNode(TreeNode node, List<TreeNode> nodes){
List<TreeNode> children = new ArrayList<TreeNode>();
if(nodes.size() > 0){
for(TreeNode n : nodes){
if(n.getParentNodeId() == node.getId()){
children.add(n);
}
}
}
if(children.size() > 0){
//排序孩子节点
Collections.sort(children);
}
return children;
}
}
这里需要注意的是,取树节点数据这个过程是在异步回调方法里面完成的。在这期间内,页面上的 ContentPanel 是已经被渲染出来了的,但这个 ContentPanel 里面的内容是空的,什么都还没有,因为这时候异步回调方法还没有执行完成,自然是没有数据。在异步回调方法的最后不要忘记去调一下 layout(true),来重新渲染一次 ContentPanel,否则面板内容是空的。
TreeNodeController
package fan.tutorial.server.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import fan.tutorial.server.commons.JsonUtil;
import fan.tutorial.server.service.DataService;
import fan.tutorial.server.value.Constant;
@Controller
@RequestMapping("/menu")
public class TreeNodeController {
@Resource
private DataService service;
@RequestMapping("/treenodes")
public String findTreeNodes(Model model){
model.addAttribute(Constant.RESULT, JsonUtil.toJson(Constant.RESULT, service.findTreeNodes()));
return Constant.RESULT_CODE;
}
}
DataService
package fan.tutorial.server.service;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import fan.tutorial.client.model.TreeNode;
import fan.tutorial.server.value.Data;
@Service
public class DataService {
@Resource
private Data data;
public List<TreeNode> findTreeNodes(){
return data.getTreeNodes();
}
}
Data
package fan.tutorial.server.value;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import fan.tutorial.client.model.TreeNode;
import fan.tutorial.client.model.TreeNode.NodeType;
@Component
public class Data {
private List<TreeNode> treeNodes;
private List<TreeNode> buildTreeNodes(){
List<TreeNode> treeNodes = new ArrayList<TreeNode>();
TreeNode usersManagementNode = new TreeNode("用户管理", NodeType.PANEL, 0);
TreeNode goodsManagementNode = new TreeNode("商品管理", NodeType.PANEL, 1);
TreeNode orderManagementNode = new TreeNode("订单管理", NodeType.PANEL, 2);
treeNodes.add(usersManagementNode);
treeNodes.add(goodsManagementNode);
treeNodes.add(orderManagementNode);
treeNodes.add(new TreeNode("系统用户管理", NodeType.ROOT, 0, usersManagementNode.getId()));
treeNodes.add(new TreeNode("会员账号管理", NodeType.ROOT, 1, usersManagementNode.getId()));
treeNodes.add(new TreeNode("在售商品", NodeType.ROOT, 2, goodsManagementNode.getId()));
treeNodes.add(new TreeNode("下架商品", NodeType.ROOT, 3, goodsManagementNode.getId()));
treeNodes.add(new TreeNode("缺货通知", NodeType.ROOT, 4, goodsManagementNode.getId()));
treeNodes.add(new TreeNode("到货通知", NodeType.ROOT, 5, goodsManagementNode.getId()));
treeNodes.add(new TreeNode("未确认订单", NodeType.ROOT, 6, orderManagementNode.getId()));
treeNodes.add(new TreeNode("待发货订单", NodeType.ROOT, 7, orderManagementNode.getId()));
treeNodes.add(new TreeNode("已发货订单", NodeType.ROOT, 8, orderManagementNode.getId()));
treeNodes.add(new TreeNode("未付款订单", NodeType.ROOT, 9, orderManagementNode.getId()));
treeNodes.add(new TreeNode("已完成订单", NodeType.ROOT, 10, orderManagementNode.getId()));
this.treeNodes = treeNodes;
return treeNodes;
}
public List<TreeNode> getTreeNodes() {
return treeNodes == null ? buildTreeNodes() : treeNodes;
}
}
TreeNodeUtil
package fan.tutorial.client.commons;
import java.util.ArrayList;
import java.util.List;
import com.extjs.gxt.ui.client.data.BaseModelData;
import com.extjs.gxt.ui.client.data.ModelData;
import fan.tutorial.client.model.ITreeNode;
import fan.tutorial.client.model.TreeNode;
import fan.tutorial.client.model.TreeNode.NodeType;
public class TreeNodeUtil {
private TreeNodeUtil(){
}
public static TreeNode modelData2TreeNode(ModelData modelData){
TreeNode node = new TreeNode();
Double id = modelData.get(ITreeNode.ID);
String text = modelData.get(ITreeNode.TEXT);
Double priorLevel = modelData.get(ITreeNode.PRIOR_LEVEL);
Double parentNodeId = modelData.get(ITreeNode.PARENT_NODE_ID);
String type = modelData.get(ITreeNode.NODE_TYPE);
NodeType nodeType = NodeType.valueOfString(type);
node.setId(id.intValue());
node.setText(text);
node.setNodeType(nodeType);
node.setPriorLevel(priorLevel.intValue());
node.setParentNodeId(parentNodeId.intValue());
return node;
}
public static List<TreeNode> modelDatas2TreeNodes(List<ModelData> modelDatas){
List<TreeNode> treeNodes = new ArrayList<TreeNode>();
for(ModelData modelData : modelDatas){
treeNodes.add(modelData2TreeNode(modelData));
}
return treeNodes;
}
public static ModelData treeNode2ModelData(TreeNode treeNode){
ModelData modelData = new BaseModelData();
modelData.set(ITreeNode.ID, treeNode.getId());
modelData.set(ITreeNode.TEXT, treeNode.getText());
modelData.set(ITreeNode.PRIOR_LEVEL, treeNode.getPriorLevel());
modelData.set(ITreeNode.PARENT_NODE_ID, treeNode.getParentNodeId());
modelData.set(ITreeNode.NODE_TYPE, treeNode.getNodeType().getValue());
return modelData;
}
public static List<ModelData> treeNodes2ModelDatas(List<TreeNode> treeNodes){
List<ModelData> modelDatas = new ArrayList<ModelData>();
for(TreeNode treeNode : treeNodes){
modelDatas.add(treeNode2ModelData(treeNode));
}
return modelDatas;
}
}
TreeNode
package fan.tutorial.client.model;
public class TreeNode implements Comparable<TreeNode> {
private int id;
private static int count;
private String text;
private NodeType nodeType;
private int priorLevel;
private int parentNodeId;
private static final int NULL = -1;
public TreeNode(){
this.id = ++count;
}
public TreeNode(String text, NodeType nodetype, int priorLevel){
this(text, nodetype, priorLevel, NULL);
}
public TreeNode(String text, NodeType nodetype, int priorLevel, int parentNodeId){
this();
this.text = text;
this.nodeType = nodetype;
this.priorLevel = priorLevel;
this.parentNodeId = parentNodeId;
}
public enum NodeType {
ROOT("ROOT"), LEAF("LEAF"), PANEL("PANEL");
private final String value;
private NodeType(String value){
this.value = value;
}
public String getValue() {
return value;
}
public static NodeType valueOfString(String value){
if(value.equals("ROOT")){
return ROOT;
}else if(value.equals("LEAF")){
return LEAF;
}else if(value.equals("PANEL")){
return PANEL;
}
return null;
}
@Override
public String toString() {
return value;
}
}
@Override
public int compareTo(TreeNode o) {
return this.priorLevel > o.priorLevel ? 1 : -1;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public NodeType getNodeType() {
return nodeType;
}
public void setNodeType(NodeType nodeType) {
this.nodeType = nodeType;
}
public int getPriorLevel() {
return priorLevel;
}
public void setPriorLevel(int priorLevel) {
this.priorLevel = priorLevel;
}
public int getParentNodeId() {
return parentNodeId;
}
public void setParentNodeId(int parentNodeId) {
this.parentNodeId = parentNodeId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
ITreeNode
package fan.tutorial.client.model;
public interface ITreeNode {
String ID = "id";
String TEXT = "text";
String NODE_TYPE = "nodeType";
String PRIOR_LEVEL = "priorLevel";
String PARENT_NODE_ID = "parentNodeId";
}