2012-01-28 191 views
8

在这里,我有一个完整且非常简单的示例,可以动态地将 节点添加到细胞树中。我的例子不太好。看起来有 是一个刷新问题。只有关闭/展开节点才会显示正确的 结果。我也没有在这个论坛上找到适合这个问题的答案。 也许有人可以尝试我的例子,并告诉我问题在哪里。 任何其他提示也非常赞赏。GWT - 在细胞树中添加和移除节点

问候,马可

import java.util.ArrayList; 
import com.google.gwt.cell.client.AbstractCell; 
import com.google.gwt.core.client.EntryPoint; 
import com.google.gwt.event.dom.client.ClickEvent; 
import com.google.gwt.event.dom.client.ClickHandler; 
import com.google.gwt.safehtml.shared.SafeHtmlBuilder; 
import com.google.gwt.user.cellview.client.CellTree; 
import com.google.gwt.user.client.ui.AbsolutePanel; 
import com.google.gwt.user.client.ui.Button; 
import com.google.gwt.user.client.ui.RootPanel; 
import com.google.gwt.view.client.ListDataProvider; 
import com.google.gwt.view.client.SingleSelectionModel; 
import com.google.gwt.view.client.TreeViewModel; 

public class MyCelltreeTest implements EntryPoint { 
    private AbsolutePanel absolutePanel; 
    private CellTree cellTree; 
    private Button btnAdd; 
    private Button btnRemove; 
    private MyTreeModel myTreeModel; 
    private SingleSelectionModel<MyNode> selectionModelCellTree = null; 

    @Override 
    public void onModuleLoad() { 
    RootPanel rootPanel = RootPanel.get(); 
    rootPanel.add(getAbsolutePanel(), 0, 0); 
    } 

    private AbsolutePanel getAbsolutePanel() { 
    if (absolutePanel == null) { 
     absolutePanel = new AbsolutePanel(); 
     absolutePanel.setSize("612px", "482px"); 
     absolutePanel.add(getCellTree(), 0, 0); 
     absolutePanel.add(getBtnAdd(), 265, 428); 
     absolutePanel.add(getBtnRemove(), 336, 428); 
    } 
    return absolutePanel; 
    } 

    private CellTree getCellTree() { 
    if (cellTree == null) { 
     myTreeModel = new MyTreeModel(); 
     cellTree = new CellTree(myTreeModel, null); 
     cellTree.setSize("285px", "401px"); 
    } 
    return cellTree; 
    } 

    private Button getBtnAdd() { 
    if (btnAdd == null) { 
     btnAdd = new Button("Add"); 
     btnAdd.addClickHandler(new ClickHandler() { 
     @Override 
     public void onClick(ClickEvent event) { 

      MyNode node = selectionModelCellTree.getSelectedObject(); 
      if(node != null) 
      myTreeModel.addNew(node, "Bla"); 
     } 
     }); 
    } 
    return btnAdd; 
    } 

    private Button getBtnRemove() { 
    if (btnRemove == null) { 
     btnRemove = new Button("Remove"); 
     btnRemove.addClickHandler(new ClickHandler() { 
     @Override 
     public void onClick(ClickEvent event) { 
      MyNode node = selectionModelCellTree.getSelectedObject(); 
      if(node != null) 
      myTreeModel.remove(node); 
     } 
     }); 
    } 
    return btnRemove; 
    } 

    public class MyNode { 
    private String name; 
    private ArrayList<MyNode> childs; //nodes childrens 
    private MyNode parent; //track internal parent 
    private MyCell cell; //for refresh - reference to visual component 

    public MyNode(String name) { 
     super(); 
     parent = null; 
     this.name = name; 
     childs = new ArrayList<MyNode>(); 
    } 

    public void addSubMenu(MyNode m) { 
     m.parent = this; 
     childs.add(m); 
    } 

    public void removeMenu(MyNode m) { 

     m.getParent().childs.remove(m); 
    } 

    public boolean hasChildrens() { 
     return childs.size()>0; 
    } 

    public ArrayList<MyNode> getList() { 
     return childs; 
    } 

    public MyNode getParent() { 
     return parent; 
    } 

    public void setCell(MyCell cell) { 
     this.cell = cell; 
    } 

    public void refresh() { 
     if(parent!=null) { 
     parent.refresh(); 
     } 
     if (cell!=null) { 
     cell.refresh(); //refresh tree 
     } 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
    } 

    public class MyTreeModel implements TreeViewModel { 
    private MyNode officialRoot; //default not dynamic 
    private MyNode studentRoot; //default not dynamic 
    private MyNode testRoot; //default not dynamic 
    private MyNode root; 

    public MyNode getRoot() { // to set CellTree root 
     return root; 
    } 

    public MyTreeModel() { 
     selectionModelCellTree = new SingleSelectionModel<MyNode>(); 
     root = new MyNode("root"); 
     // Default items 
     officialRoot = new MyNode("Cat"); //some basic static data 
     studentRoot = new MyNode("Dog"); 
     testRoot = new MyNode("Fish"); 
     root.addSubMenu(officialRoot); 
     root.addSubMenu(studentRoot); 
     root.addSubMenu(testRoot); 
    } 

    //example of add add logic 
    public void addNew(MyNode myparent, String name) { 
     myparent.addSubMenu(new MyNode(name)); 
     myparent.refresh(); //HERE refresh tree 
    } 
    public void remove(MyNode objToRemove) { 

     objToRemove.removeMenu(objToRemove); 
     objToRemove.refresh(); 
    } 

    @Override 
    public <T> NodeInfo<?> getNodeInfo(T value) { 
     ListDataProvider<MyNode> dataProvider; 
     MyNode myValue = null; 
     if (value == null) { // root is not set 
     dataProvider = new ListDataProvider<MyNode>(root.getList()); 
     } else { 
     myValue = (MyNode) value; 
     dataProvider = new ListDataProvider<MyNode>(myValue.getList()); 
     } 
     MyCell cell = new MyCell(dataProvider); //HERE Add reference 
     if (myValue != null) 
     myValue.setCell(cell); 
     return new DefaultNodeInfo<MyNode>(dataProvider, cell, selectionModelCellTree, null); 
    } 

    @Override 
    public boolean isLeaf(Object value) { 
     if (value instanceof MyNode) { 
     MyNode t = (MyNode) value; 
     if (!t.hasChildrens()) 
      return true; 
     return false; 
     } 
     return false; 
    } 
    } 

    public class MyCell extends AbstractCell<MyNode> { 
    ListDataProvider<MyNode> dataProvider; //for refresh 

    public MyCell(ListDataProvider<MyNode> dataProvider) { 
     super(); 
     this.dataProvider = dataProvider; 
    } 
    public void refresh() { 
     dataProvider.refresh(); 
    } 

    @Override 
    public void render(Context context, MyNode value, SafeHtmlBuilder sb) { 
     if (value == null) { 
     return; 
     } 
     sb.appendEscaped(value.getName()); 
    } 
    } 
} 

感谢乌米特感谢你的解释。 我试过了close-reopen版本。 我用下面的方法替换了我的刷新方法。 添加正在工作,但未删除。 整个话题都很奇怪。我很惊讶这些基本的功能并不是GWT真正支持的。 有人能给我更多的帮助来运行一个真实的工作示例。

public void refresh() { 

     closeReopenTreeNodes(cellTree.getRootTreeNode()); 
    } 

    private void closeReopenTreeNodes(TreeNode node) { 
     if(node == null) { 
      return; 
     } 
     for(int i = 0; i < node.getChildCount(); i++) { 

      if(node.getChildValue(i).equals(this)){ 

       if(node.getParent() != null){ 

        node.getParent().setChildOpen(i, false); 
        //node.getParent().setChildOpen(i, true); 
       } 

       node.setChildOpen(i, false); 
       node.setChildOpen(i, true); 
      }    
      TreeNode child = node.setChildOpen(i, node.isChildOpen(i)); 
      closeReopenTreeNodes(child); 
     } 
    } 

这里我第三次尝试: 这种方式是通过GWT-commiter建议。 请参阅以下问题: http://code.google.com/p/google-web-toolkit/issues/detail?id=7160

现状: *添加可能 *删除是可能的,如果不是最后一个孩子!

那么,最后一个开放点,如果最后一个开放的孩子刷新树!

package com.test; 

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Map; 

import com.google.gwt.cell.client.AbstractCell; 
import com.google.gwt.core.client.EntryPoint; 
import com.google.gwt.event.dom.client.ClickEvent; 
import com.google.gwt.event.dom.client.ClickHandler; 
import com.google.gwt.safehtml.shared.SafeHtmlBuilder; 
import com.google.gwt.user.cellview.client.CellTree; 
import com.google.gwt.user.client.ui.AbsolutePanel; 
import com.google.gwt.user.client.ui.Button; 
import com.google.gwt.user.client.ui.RootPanel; 
import com.google.gwt.view.client.ListDataProvider; 
import com.google.gwt.view.client.SingleSelectionModel; 
import com.google.gwt.view.client.TreeViewModel; 

public class MyCelltreeTest2 implements EntryPoint { 
    private AbsolutePanel absolutePanel; 
    private CellTree cellTree; 
    private Button btnAdd; 
    private Button btnRemove; 
    private MyTreeModel myTreeModel; 
    private SingleSelectionModel<MyNode> selectionModelCellTree = null; 
    private Map<MyNode, ListDataProvider<MyNode>> mapDataProviders = null; 
    private ListDataProvider<MyNode> rootDataProvider = null; 

    public void onModuleLoad() { 
      RootPanel rootPanel = RootPanel.get(); 
      rootPanel.add(getAbsolutePanel(), 0, 0); 
    } 

    private AbsolutePanel getAbsolutePanel() { 
      if (absolutePanel == null) { 
        absolutePanel = new AbsolutePanel(); 
        absolutePanel.setSize("612px", "482px"); 
        absolutePanel.add(getCellTree(), 0, 0); 
        absolutePanel.add(getBtnAdd(), 265, 428); 
        absolutePanel.add(getBtnRemove(), 336, 428); 
      } 
      return absolutePanel; 
    } 
    private CellTree getCellTree() { 
      if (cellTree == null) { 
        myTreeModel = new MyTreeModel(); 
        cellTree = new CellTree(myTreeModel, null); 
        cellTree.setSize("285px", "401px"); 
      } 
      return cellTree; 
    } 
    private Button getBtnAdd() { 
      if (btnAdd == null) { 
        btnAdd = new Button("Add"); 
        btnAdd.addClickHandler(new ClickHandler() { 
          public void onClick(ClickEvent event) { 

        MyNode node = selectionModelCellTree.getSelectedObject(); 

           myTreeModel.add(node, "Bla"); 
          } 
        }); 
      } 
      return btnAdd; 
    } 
    private Button getBtnRemove() { 
      if (btnRemove == null) { 
        btnRemove = new Button("Remove"); 
        btnRemove.addClickHandler(new ClickHandler() { 
          public void onClick(ClickEvent event) { 

          MyNode node = selectionModelCellTree.getSelectedObject(); 

            myTreeModel.remove(node); 
          } 
        }); 
      } 
      return btnRemove; 
    } 


    public class MyNode { 

     private String name; 
     private ArrayList<MyNode> childs; //nodes childrens 
     private MyNode parent; //track internal parent 


     public MyNode(String name) { 
      super(); 
      parent = null; 
      this.name = name; 
      childs = new ArrayList<MyNode>(); 
     } 
     public boolean hasChildrens() { 
      return childs.size()>0; 
     } 
     public ArrayList<MyNode> getList() { 
      return childs; 
     } 
     public MyNode getParent() { 
      return parent; 
     } 

     public String getName() { 
      return name; 
     } 
     public void setName(String name) { 
      this.name = name; 
     }  
    } 

    public class MyTreeModel implements TreeViewModel { 


     public MyTreeModel() { 
      selectionModelCellTree = new SingleSelectionModel<MyNode>(); 
      mapDataProviders = new HashMap<MyCelltreeTest2.MyNode, ListDataProvider<MyNode>>(); 
     } 

     public void add(MyNode myparent, String name) { 

      MyNode child = new MyNode(name); 

      //root-node 
      if(myparent == null){ 
        rootDataProvider.getList().add(child); 
        mapDataProviders.put(child, rootDataProvider); 
      } 
      else{ 

        ListDataProvider<MyNode> dataprovider = mapDataProviders.get(myparent); 
        myparent.childs.add(child); 
        child.parent = myparent; 
        dataprovider.refresh(); 
      } 
     } 
     public void remove(MyNode objToRemove) { 

      ListDataProvider<MyNode> dataprovider = mapDataProviders.get(objToRemove); 
        dataprovider.getList().remove(objToRemove); 
    //     mapDataProviders.remove(objToRemove); 
        dataprovider.refresh(); 
        dataprovider.flush(); 

        if(objToRemove.parent != null){ 
          ListDataProvider<MyNode> dataproviderParent = mapDataProviders.get(objToRemove.parent); 
          objToRemove.parent.childs.remove(objToRemove); 
          dataproviderParent.refresh(); 
          dataproviderParent.flush(); 
        } 
        else{ 
          rootDataProvider.refresh(); 
          rootDataProvider.flush(); 
        }  
     } 


     @Override 
     public <T> NodeInfo<?> getNodeInfo(T value) { 

      if (value == null) { // root is not set 
      rootDataProvider = new ListDataProvider<MyNode>(new ArrayList<MyNode>()); 
        MyCell cell = new MyCell(); 
    return new DefaultNodeInfo<MyNode>(rootDataProvider, cell, 
    selectionModelCellTree, null); 
      } else { 
        MyNode myValue = (MyNode) value; 
       ListDataProvider<MyNode> dataProvider = 
        new ListDataProvider<MyNode>(myValue.childs); 
        MyCell cell = new MyCell(); 
        for(MyNode currentNode : myValue.childs){ 
          mapDataProviders.put(currentNode, dataProvider); 
        } 
       return new DefaultNodeInfo<MyNode>(dataProvider, cell, 
       selectionModelCellTree, null); 
      } 
     } 

     @Override 
     public boolean isLeaf(Object value) { 
      if (value instanceof MyNode) { 
       MyNode t = (MyNode) value; 
       if (!t.hasChildrens()) 
        return true; 
       return false; 
      } 
      return false; 
     } 

    } 

    public class MyCell extends AbstractCell<MyNode> { 
      public MyCell() { 
       super(); 
      } 
      @Override 
      public void render(Context context, MyNode value, SafeHtmlBuilder sb) { 
       if (value == null) { 
       return; 
       } 
       sb.appendEscaped(value.getName()); 
      } 
    } 
} 
+0

有没有人干净利落地绕过它?令人沮丧的是,这是根据GWT发布者设计的 - http://code.google.com/p/google-web-toolkit/issues/detail?id=7160 – SSR 2013-02-11 03:28:00

回答

5

这在某种程度上是CellTree的一个已知问题。
刷新问题的原因是在getNodeInfo()函数中为每个CellTree级别创建一个新的ListDataProvider实例。
如果您更新ListDataProvider中的项目,CellTree只更新/刷新自身。 我相信你的removeMenu()和addSubMenu()函数添加和删除存储在MyNode类中的原始列表中的项目,但不会更新相应ListDataProviders中的列表(可以尝试在调试模式下检查它)。
当你关闭和重新打开CellTree时,打开这个节点的原因是因为当你重新打开节点时,将再次调用getNodeInfo(),并且整个CellTree结构将被重新构造(包括新菜单或没有分别去除一个)。

有两种可能的解决方案:

  1. 请参考每个ListDataProviders某处,并调用删除/添加列表中(虽然你这样做,我认为该项目是不是真的添加/删除有)。
  2. 以编程方式关闭所有节点并重新打开它。

两者都以某种方式实施PITA。不幸的是,它没有简单的方法。

+0

感谢您的解释。我尝试了重新打开的版本。添加正在工作,但没有移除。你有一个完整的工作示例,为您的建议解决方案之一? – user1165474 2012-01-29 16:09:15

+0

明天或者明天第三天我会发布密码重新打开 – 2012-01-30 12:30:12

+0

HiÜmit,你有没有例子?我仍然没有找到解决办法。 – user1165474 2012-02-03 14:32:54

0

我只是清除了我的数据提供程序中维护的对象数组。我在onRangeChanged(final HasData<?> display)中这样做。我想我在这里不使用ListDataProvider,我使用延伸AbstractDataProvider<T>的东西来代替。

要添加节点,请将其添加到onRangeChanged()方法中的列表中,然后拨打updateRowData()。您也可以为此进行删除。

0

我想我可能已经舔问题...

基本上我已经扩展和子类CellTree的许多地方,并取得了一个近乎完美的工作的例子。这里的文档太复杂了,但足以说明使用节点类所涉及的解决方案,其中我在每个节点中存储了数据提供者。

https://code.google.com/p/updatable-cell-tree/

+0

尽管这个链接可能回答这个问题,但最好在这里包含答案的基本部分并提供链接供参考。如果链接页面更改,则仅链接答案可能会失效。 – chris 2013-10-20 08:33:50

+0

够公平的,但如果你花时间真正看待答案,那就不太实际。这个解决方案不是简单的包含在这里吗? – gslender 2013-10-24 13:17:11