MyFaces Tree2控件使用 -----From http://blog.163.com/net_wood/blog

简介:
MyFaces开源网站:   http://www.irian.at/myfacesexamples/home.jsf
================================================

通过一次小小的实践,终于了解如何使用tomahawk中的tree2这个组件了,并且写了小段程序,从xml中读取树的结构,生成一个tree,不过tree2不能直接和xml绑定是一个遗憾,那样就会省不少事情了。记下一点心得,以供后来参考了。

         tree2的操作分为两部分,一部分是在页面中通过tag定义样式相关的东西,一部分就是通过编程添加树的节点,起初看了sample以后总是以为这东西有多么的复杂,其实逻辑是很简单的,只是sample中定义了多种不同的样式的节点,看上去很复杂而已。

下面附上我对sample简化过的这段tag来说明一下。

<t:tree2 value="#{catalog.node}" var="node" >"clientside" varNodeToggler="t" >

    <f:facet >"folder">

        <h:panelGroup>

            <f:facet >"expand">

                <t:graphicImage value="images/yellow-folder-open.png" rendered="#{t.nodeExpanded}" border="0"/>

            </f:facet>

            <f:facet >"collapse">

                <t:graphicImage value="images/yellow-folder-closed.png" rendered="#{!t.nodeExpanded}" border="0"/>

            </f:facet>

            <h:outputText value="#{node.description}"/>

        </h:panelGroup>

    </f:facet>

</t:tree2>

tree2的主tag定义了tree的根节点和一些相关的参数。嵌套的那个facet定义了一种节点的样式,包括展开与关闭时的图片,以及显示的文字内容。

在程序里面,我们root TreeNodeBase = new TreeNodeBase(…)来创建一个root节点,然后通过root.getChildren().add(new TreeNodeBase(…))为其添加子节点,任何一个节点都可以添加任意多的子节点,通过这样的操作,我们可以很容易的生成一个tree的结构了,实际上,这个tree的结构是通过递归从xml中读取出来,生成一个和xml tree完全相同的结构。

除了明白如何去用这个tree2之外的收获就是,终于明白了如何去通过递归方法遍历一个树形结构,虽然在学校里学过遍历的算法,也抄过例程,但从来没有理解过是怎么一回事,终于在实践中理解了,实践才是软件的根本之道。
   程序的其它部分放在附件里面了,如果有兴趣了可以和我讨论tree2,讨论其它JSF的东西。
   http://www.blogjava.net/Files/steady/catalog.rar

先拿回来收藏了再说,等验证后再把结果贴出来。
===========================================================================================
析Tree2(一)  原址:http://www.blogjava.net/steady/archive/2006/01/13/27904.html

在我的 blog 中,JSF Tree2 组件一直都是一个热门的讨论话题,为了向大家介绍更多关于Tree2的内容,我翻译了这篇原产于 Apache Myfaces 社区的介绍 Tree2 的文章,希望大家能够对 Tree2 有更深的认识。

在最后会附上一些我在使用中的体会,和大家分享,如果大家有什么想法的话,可以和我多多交流了。本人第一次翻译文章,难免会有很多不足之处,请大家谅解,也请多多指点。

英文原作:http://www.blogjava.net/steady/archive/2006/01/12/27814.html

转载自:http://wiki.apache.org/myfaces/Tree2

正文如下:

Tree2组件使用HTML表格将你的数据呈现为一个树。这个树是动态的:当用户点击它们时它们可以展开或者折叠。该组件同时支持客户端和服务端的交互方式,在客户端交互时使用了JavaScript。在随后的例子中,每次用户的点击将产生一个Request / Response 周期,并在新的视图状态(View State)中重新呈现新的树结构。

注:在后面的例子中只有可见的(已经展开的节点)数据被传送到客户端。而在第一个例子(客户端Tree),在每个HTML Response中,整个树都被发送到客户端浏览器。树的每个节点都包含了不少的HTML代码(假定每个节点200个字符,这个大小将取决于你希望在节点上显示的信息的量),这些信息将被传送到浏览器,其中包括了那些不可见的节点(没有展开的节点),因为它们的一个祖系节点被展开。如果你有一个深度有四层的树,平均每个结点拥有四个子结点,这时候你就需要传输10 + 102 + 103 + 104 = 11 110个节点,每个节点有200个字符,这个树总共就有2 222 000个字符,也就是2M的数据。这个例子将向用户说明,虽然纯客户端Tree会给客户端带来更好的用户体验,但随之而来的带宽问题迅速的增长。纯客户端的树适用于小型的树,或者在Intranet及宽带连接中使用的中型大小的树。对于大型的树,或者你需要照顾到一些低带宽的用户的需要时,(建议使用服务端,否则页面显式会很慢)你就需要使用服务端树。你可以通过<t:tree2>clientSideToggle这个属性来选择你使用的是客户端的树或者服务端的树,<t:tree2 clientSideToggle="false" ...将会使用服务端的树,属性值设为true将会使用客户端的树,默认值为true。

用法:

Backing Bean:

Tree2组件对Backing Bean中的一个TreeModel进行操作。通常情况,你只要把这个TreeModel绑定到这个组件上就可以了,就像这样:

< t:tree2  value ="#{myHandler.treeModel}"  


下面需要建立一个类MyHandler,在faces-config.xml中的managed bean配置成myHandler,在例子中这个类提供了一个方法getTreeModel()用于返回一个TreeModel用于表示你的数据。

public  class  MyHandler  {
  public TreeModel getTreeModel() {
    
  }

}


TreeModel实际上是对TreeNode实例进行了一些简单的包装。

TreeNode是一个接口,其中和tree2相关有四个方法:

String getType()

boolean isLeaf()

List getChildren()

int getChildCount()

其它方法都没有什么用处了,可能会在今后的版本中取消。它们要求开发者在开发backing bean中做一些并不必要的操作。

int getChildCount()方法返回这个节点的子结点数量,这个方法了很容易的采用如下的方式实现:

   public  final  int  getChildCount()  {
    return getChildren().size();
  }


该方法的出现使得对于子结点的延迟加载变的可行。该方法的实现只需要返回该节点的子结点数量,而不需要返回每个子结点的实例。

boolean isLeaf() 方法在该节点没有子节点的时候返回true。这样,一个很直截了当的实现可以这样:

   public  final  boolean  isLeaf()  {
    return getChildren().isEmpty();
  }


不管你提供了什么样的实现,在任何时间任何情况下你都得保持getChildren().isEmpty() ==> isLeaf()。isLeaf()方法实际上控制了节点被怎样呈现:是否被当做树叶节点(不能被继续展开)。

String getType() 方法决定了用怎样的方式来呈现这个节点。在 JSF 页面中,可以在 <t:tree2> 的Tag 中嵌套facet,JSF将会选出与 getType() 方法返回值同名的 facet 用于呈现。如果该节点没有找到相符的 facet,将会导致一个错误,并且这个方法不会返回null。

List getChildren() 方法返回一个 List,其中包含了该节点下所有的 TreeNode,这就表示这些节点将被呈现为该节点下的子结点。该 List 不能包含 null,如果该 List 的大小和getChildCount()不符,将会报错。子结点将按照它们在 List 中的顺序呈现出来。
==================================================
JSF TREE2 例子-- JAVA类文件   [折叠] 

package cn.bizprocess.sysmanage.user.web.webtree;

import java.io.Serializable;
import java.util.Iterator;
import java.util.*;

import org.apache.myfaces.custom.tree2.TreeNodeBase;

import cn.common.exception.BizException;
import cn.common.model.bo.PubCodeBO;
import cn.common.web.BaseBackingBean;
import cn.bizprocess.sysmanage.user.ucc.ISysParameterUCC;

/** 
 * <p>Title:DictTree</p> 
 * 
 * <p>Description: 系统参数(数据字典)管理类</p> 
 */
public class DictTree  extends BaseBackingBean implements Serializable  {

 private static final long serialVersionUID = 1L;
 private String _nodePath;
 private TreeNodeBase TreeNode;
 private ISysParameterUCC sysParameterUCC;
 private PubCodeBO sysParameterBO;
 
 TreeNodeBase temp2;
 
 /**
  * 获得系统代码树
  * @return
  * @throws Exception
  */
    public TreeNodeBase getBranchTree() throws BizException  {   
     
        try  {
         sysParameterBO=sysParameterUCC.querySysParameterByParentCodeNo("-1");
         String parent_code_no=sysParameterBO.getCodeNo();
         
         if ((sysParameterUCC.getChildPubCodeBOs(parent_code_no)).size()>0) {
          TreeNode=new TreeNodeBase("parent",sysParameterBO.getPubCodeId().toString(),sysParameterBO.getCodeName(), false);
          TreeNode=findBranchChild_Branch(TreeNode,sysParameterBO);
         }
         else  {
          TreeNode=new TreeNodeBase("parent",sysParameterBO.getPubCodeId().toString(),sysParameterBO.getCodeName(), true);
         }  
        }
        catch(BizException biz) {
         this.exceptionMsg.setMainMsg(biz);
        }
        return TreeNode;
    }
    
    /**
  * 查询子代码
  * @param superNode
  * @param superBO
  * @return
  * @throws Exception
  */    
    public TreeNodeBase findBranchChild_Branch(TreeNodeBase superNode,PubCodeBO superBO) throws BizException {    
    
     try{
      PubCodeBO childBO=new PubCodeBO();
      List childlist=sysParameterUCC.getChildPubCodeBOs(superBO.getCodeNo());
   Iterator it =childlist.iterator();
   
    while(it.hasNext()) {
     
    childBO=(PubCodeBO)it.next();
    
    //System.out.println("2222222222222222222----------------FFF--------------"+childBO);
    
    List ss_list=(sysParameterUCC.getChildPubCodeBOs(childBO.getCodeNo()));
    if (ss_list!=null) {
      temp2=new TreeNodeBase("parent",childBO.getPubCodeId().toString(),childBO.getCodeName(), false);
    }
    else {
      temp2=new TreeNodeBase("parent",childBO.getPubCodeId().toString(),childBO.getCodeName(), true);
    }    
    superNode.getChildren().add(temp2);
    
    if ((sysParameterUCC.getChildPubCodeBOs(childBO.getCodeNo()))!=null) {
     temp2=findBranchChild_Branch(temp2,childBO);
    }    
         }
     }
     catch(BizException biz) {
      throw biz;
     }
  return superNode;
    }
    
    /**
  * @return 返回 sysParameterBO。
  */
 public PubCodeBO getSysParameterBO() {
  return sysParameterBO;
 }

 /**
  * @param sysParameterBO 要设置的 sysParameterBO。
  */
 public void setSysParameterBO(PubCodeBO sysParameterBO) {
  this.sysParameterBO = sysParameterBO;
 }
 
    /**
  * @return 返回 sysParameterUCC。
  */
 public ISysParameterUCC getSysParameterUCC() {
  return sysParameterUCC;
 }

 /**
  * @param sysParameterUCC 要设置的 sysParameterUCC。
  */
 public void setSysParameterUCC(ISysParameterUCC sysParameterUCC) {
  this.sysParameterUCC = sysParameterUCC;
 }
    
    public void setNodePath(String nodePath) {
        _nodePath = nodePath;
    }

    public String getNodePath() {
        return _nodePath;
    }

 public TreeNodeBase getTreeNode() {
  return TreeNode;
 }

 public void setTreeNode(TreeNodeBase treeNode) {
  TreeNode = treeNode;
 }
}

=======================================================================

原址:http://www.blogjava.net/steady/archive/2006/01/13/27960.html

改变Tree中的内容

(当展开树的节点时,在后台延迟加载)

在邮件列表中有很多关于这项任务的问题和讨论,我(Marcel,一个 JSF 的初学者)在这里总结一下。如果你有更好的解决方案,请更新这些文字。

在这里存在的一个问题就是我要这样把“+”图标去掉:

·         <t:tree2 ... showNav="false" ...>

然后再让文件夹图标(代表包含子节点的节点)变的可点击:

·         <h:commandLink action="#{t.toggleExpanded}" actionListener="#{navigationBacker.processAction}">

然后在 Java 代码中接受鼠标点击的事件。在 NavigationBacker.java 文件中的processAction(ActionEvent e) 方法里,我从 EJB3-persistency 中加载子结点的数据。

不好的是“+”图标变的不可见,但是我现在没有办法获取点击“+”图标的事件。

看起来在org.apache.myfaces.custom.tree2.HtmlTree.java这个文件里是通过注册了_expandControl = new HtmlCommandLink(); 从内部获取“+”的点击事件,但是我现在没有办法从我的代码中接受到这一事件。

为了导航,我使用了含有entries的TreeNode.getIdentifier() (参见:#{node.identifier}),看起来就是这个样子:

·         db_id="car_id=7,person_id=2"

这代表了后台数据库表的主键(我还没有找到一个更好的解决方案用于导航)

程序代码如下:

navigation.jsp 

   < t:tree2  id ="serverTree"  value ="#{navigationBacker.treeData}"
    var
="node"  varNodeToggler ="t"  clientSideToggle ="false"  showNav ="false"
    showRootNode
="false" >
    
< f:facet  name ="project-folder" >
      
< h:panelGroup >
        
< h:commandLink  action ="#{t.toggleExpanded}"  actionListener ="#{navigationBacker.processAction}" >
            
< t:graphicImage  value ="/images/yellow-folder-open.png"
                rendered
="#{t.nodeExpanded}"  border ="0"  />
            
< t:graphicImage  value ="/images/yellow-folder-closed.png"
                rendered
="#{!t.nodeExpanded}"  border ="0"  />
        
</ h:commandLink >
        
< h:commandLink  action ="#{navigationBacker.toViewId}"
            styleClass
="#{t.nodeSelected ? 'documentSelected':'document'}"
            actionListener
="#{navigationBacker.nodeClicked}"
            value
="#{node.description}"  immediate ="true" >
            
< f:param  name ="db_id"  value ="#{node.identifier}"  />
            
        
</ h:commandLink >
        
< h:outputText  value =" (#{node.childCount})"  styleClass ="childCount"
            rendered
="#{!empty node.children}"  />
      
</ h:panelGroup >
    
</ f:facet >
    
< f:facet  name ="person-folder" >
      
< h:panelGroup >

NavigationBacker.java 

     /**
     * 拦截节点被展开的事件,并加载额外的数据
     * 
@param event
     * 
@throws AbortProcessingException
     
*/

    
public  void  processAction(ActionEvent event)  throws  AbortProcessingException  {
            System.out.println("Entering processAction()");
            UIComponent component 
= (UIComponent) event.getSource();
            
while (!(component != null && component instanceof HtmlTree)) {
                    component = component.getParent();
            }

            
if (component != null{
                    HtmlTree tree = (HtmlTree) component;
                    TreeNodeBase node 
= (TreeNodeBase) tree.getNode();
                    
if (!tree.isNodeExpanded() && node.getChildren().size() == 0{
                        Map<String, String> map = splitKeyValues(node.getIdentifier()); // 一些辅助代码,用于将 "car_id=7" 或 "car_id=7&person_id=12" 拆分开
                        this.car_id = map.get("car_id");
                        
if (this.car_id != null{
                            appendPersonsNodes(node); // 参见下面的例子
                        }

                        
this.person_id = map.get("person_id");
                        
if (this.person_id != null{
                            appendLicensesNodes(node); // 没有显示
                        }

                    }

            }

    }


    
/** 把当前car_id下的Person子结点加入导航中 */
    
private  void  appendPersonsNodes(TreeNodeBase carDetailNode)  {
        VariableResolver resolver = FacesContext.getCurrentInstance()
        .getApplication().getVariableResolver();
        PersonsTable personsTable 
= (PersonsTable) resolver
                .resolveVariable(FacesContext.getCurrentInstance(),
                        
"personsTable");
        List
<Person> personsList = personsTable.getCarPersons();
        
for (Person o : personsList) {
            List<TreeNodeBase> list = carDetailNode.getChildren();
            list.add(
new TreeNodeBase("person-folder", o.getDescription(),
                            
"person_id=" + o.getPersonId(), true));
        }

        System.out.println(
"NavigationBacker fetched " + personsList.size() + " Persons for carId=" + this.car_id);
    }


这里有一段辅助代码用于从 h:commandLink 中获取 f:param 用于多种用途。

     /**
     * 当 JSF 组件 h:commandLink 包含有 f:param 成员, 这些 name-value 对被放到 
* request 参数表中供后面的action handler使用。不幸的是,这样的用法不能用在
* h:commandButton上。我们没有办法把通过 button 来传递这些参数。
     *
     * 因为 Action Listeners 可以保证在 Action 方法前被执行到,所以 Action Listeners 
* 可以调用该方法更新 Action 方法所需要的任何上下文。
     *
     * From 
http://cvs.sakaiproject.org/release/2.0.0/
     * sakai2/gradebook/tool/src/java/org/sakaiproject/tool/gradebook/jsf/FacesUtil.java
     * Educational Community License Version 1.0
     
*/

    
public  static  final  Map getEventParameterMap(FacesEvent event)  {
        Map<String, String> parameterMap = new HashMap<String, String>();
        List children 
= event.getComponent().getChildren();
        
for (Iterator iter = children.iterator(); iter.hasNext();) {
            Object next = iter.next();
            
if (next instanceof UIParameter) {
                UIParameter param = (UIParameter) next;
                parameterMap.put(param.getName(), 
"" + param.getValue());
            }

        }

        
//System.out.println("parameterMap=" + parameterMap);
        return parameterMap;
    }


注:在上面的例子里,backing bean都存放于 session 作用域里,可以在WEB-INF/examples-config.xml 中进行配置。

 

很多朋友和我交流了一些有关 Tree2 的问题,我把一些大家经常碰到的问题拿出来,希望刚开始学习的朋友能够避免再犯一些这样的错误。

1.首先就是关于 myfaces 包的问题,Myfaces 1.1.1 release 版本的 Tree2 是有 bug 的,大概在十一月份的时候修正了大部分问题,但是由于这以后并没有 release 版本出来,所以大家可以使用一些较新一点的 Nightly Build,可以去这里找找http://cvs.apache.org/builds/myfaces/nightly/ ,不过从元旦后似乎改用了 Maven 后还没有一个 Build 出来,我手上有一个12.30 Build的版本,如果需要的话可以和我联系。因为这些 Nightly Build 不确定可能还会有其它的一些问题,所以用的时候要慎重一点。

2. 有些朋友就直接把代码贴上去用,会碰到一些诸如点击没有反应或者图标显示不出来的问题,很多时候是因为没有加上MyFaces' Extensions Filter,相关的内容可以参考我前面写的http://www.blogjava.net/steady/archive/2005/11/17/20170.html

希望这两篇介绍 Tree2 的文章能给大家一些新的认识,今后也会努力拿出更多更好的东西来和大家分享

本文转自kenty博客园博客,原文链接http://www.cnblogs.com/kentyshang/archive/2008/06/05/1214087.html如需转载请自行联系原作者


kenty

相关文章
|
4月前
|
开发框架 JavaScript 前端开发
震撼!破解 ASP.NET 服务器控件 Button 执行顺序之谜,颠覆你的开发认知!
【8月更文挑战第16天】在ASP.NET开发中,通过Button控件实现先执行JavaScript再触后台处理的需求十分常见。例如,在用户点击按钮前需前端验证或提示,确保操作无误后再传递数据至后台深度处理。此过程可通过设置Button的`OnClientClick`属性调用自定义JavaScript函数完成验证;若验证通过,则继续触发后台事件。此外,结合jQuery也能达到相同效果,利用`__doPostBack`手动触发服务器端事件。这种方式增强了应用的交互性和用户体验。
51 8
|
2月前
|
开发者 Windows
.NET 开源扁平化、美观的 C/S 控件库
【10月更文挑战第23天】介绍了三款适用于 .NET 平台的开源扁平化、美观的 C/S 控件库:MaterialSkin 采用 Google Material Design 风格,适合现代感界面;Krypton Toolkit 提供丰富控件,界面易于定制;Fluent Ribbon Control Suite 模仿 Office 界面,适合复杂功能应用。每款控件库均附有示例代码及 GitHub 链接。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
2月前
|
C# Android开发 iOS开发
一组.NET MAUI绘制的开源控件 - AlohaKit
一组.NET MAUI绘制的开源控件 - AlohaKit
|
4月前
|
数据采集 JSON API
异步方法与HTTP请求:.NET中提高响应速度的实用技巧
本文探讨了在.NET环境下,如何通过异步方法和HTTP请求提高Web爬虫的响应速度和数据抓取效率。介绍了使用HttpClient结合async和await关键字实现异步HTTP请求,避免阻塞主线程,并通过设置代理IP、user-agent和cookie来优化爬虫性能。提供了代码示例,演示了如何集成这些技术以绕过目标网站的反爬机制,实现高效的数据抓取。最后,通过实例展示了如何应用这些技术获取API的JSON数据,强调了这些方法在提升爬虫性能和可靠性方面的重要性。
异步方法与HTTP请求:.NET中提高响应速度的实用技巧
|
3月前
|
开发框架 JavaScript 前端开发
|
7月前
|
存储 网络协议 Go
7天玩转 Golang 标准库之 http/net
7天玩转 Golang 标准库之 http/net
63 2
|
7月前
|
JSON 编解码 Go
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第25天】Go语言`net/http`包提供HTTP客户端和服务器功能,简化高性能网络应用开发。本文探讨如何发起HTTP请求,常见问题及解决策略。示例展示GET和POST请求的实现。注意响应体关闭、错误处理、内容类型设置、超时管理和并发控制。最佳实践包括重用`http.Client`,使用`context.Context`,处理JSON以及记录错误日志。通过实践这些技巧,提升HTTP编程技能。
85 1
|
7月前
|
JSON API 定位技术
.NET集成DeveloperSharp实现http网络请求&与其它工具的比较
该内容介绍了一个支持.NET Core 2.0及以上和.NET Framework 4.0及以上的HTTP请求调用方法,主要讨论了POST和GET两种形式。POST请求较为常见,涉及调用地址、发送参数、HTTP请求头和编码格式设置。文中提供了一个使用DeveloperSharp库发送POST请求的C#代码示例,用于发送短信,其中`IU.HttpPost`方法用于执行POST请求。此外,还提到了`HttpPost`方法的参数和返回值说明。最后简要提及了GET请求,通常用于URL带有查询参数的情况,并给出一个简单的GET请求示例。
|
7月前
|
Go 开发者
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第24天】Go语言的`net/http`包在HTTP客户端编程中扮演重要角色,但使用时需注意几个常见问题:1) 检查HTTP状态码以确保请求成功;2) 记得关闭响应体以防止资源泄漏;3) 设置超时限制,避免长时间等待;4) 根据需求处理重定向。理解这些细节能提升HTTP客户端编程的效率和质量。
82 1