<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent.Chan‘s Blog

    常用鏈接

    統計

    積分與排名

    網站

    最新評論

    轉載:解析Tree2

     

    在我的 blog 中,JSF Tree2 組件一直都是一個熱門的討論話題,為了向大家介紹更多關于Tree2的內容,我翻譯了這篇原產于 Apache Myfaces 社區的介紹 Tree2 的文章,希望大家能夠對 Tree2 有更深的認識。

    在最后會附上一些我在使用中的體會,和大家分享,如果大家有什么想法的話,可以和我多多交流了。本人第一次翻譯文章,難免會有很多不足之處,請大家諒解,也請多多指點。

    英文原作:http://www.tkk7.com/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 中嵌套facetJSF將會選出與 getType() 方法返回值同名的 facet 用于呈現。如果該節點沒有找到相符的 facet,將會導致一個錯誤,并且這個方法不會返回null。

    List getChildren() 方法返回一個 List,其中包含了該節點下所有的 TreeNode,這就表示這些節點將被呈現為該節點下的子結點。該 List 不能包含 null,如果該 List 的大小和getChildCount()不符,將會報錯。子結點將按照它們在 List 中的順序呈現出來。

      

    改變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(); 從內部獲取“+”的點擊事件,但是我現在沒有辦法從我的代碼中接受到這一事件。

    為了導航,我使用了含有entriesTreeNode.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.tkk7.com/steady/archive/2005/11/17/20170.html。


    posted on 2006-01-14 03:40 Vincent.Chen 閱讀(352) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 中字幕视频在线永久在线观看免费| 国产乱子影视频上线免费观看| 1000部拍拍拍18勿入免费凤凰福利| 亚洲乱码在线视频| 国产美女a做受大片免费| 香蕉视频在线免费看| 亚洲国产精品线观看不卡| 四只虎免费永久观看| 日韩人妻一区二区三区免费| 亚洲日韩国产欧美一区二区三区 | 国产亚洲精品精品国产亚洲综合| 最新亚洲精品国偷自产在线| 亚洲午夜精品一级在线播放放 | 亚洲综合图片小说区热久久| 免费在线观看毛片| 一级毛片免费毛片一级毛片免费 | 午夜理伦剧场免费| 亚洲AV无码成人精品区日韩| 日韩激情无码免费毛片| 国产免费无码一区二区| 亚洲国产精品成人久久| 麻豆成人精品国产免费| 男人进去女人爽免费视频国产| 亚洲精品无码你懂的| 亚洲成人中文字幕| 亚洲国产精品激情在线观看| 青青青免费国产在线视频小草| igao激情在线视频免费| 亚洲男人天堂2018av| 亚洲an天堂an在线观看| 亚洲中文字幕无码爆乳av中文| 日韩精品无码区免费专区 | 又粗又硬免费毛片| 男人的好看免费观看在线视频| 在线播放免费人成毛片乱码| 理论秋霞在线看免费| 自拍偷区亚洲国内自拍| 亚洲综合一区二区| 亚洲AV日韩AV天堂一区二区三区| 亚洲视频一区二区| 国产精品美女自在线观看免费|