GWT - 在celltree中添加和删除节点

时间:2012-01-28 10:50:55

标签: gwt add

这里有一个完整且非常简单的动态添加/删除示例 节点到celltree。我的例子不是很好。它似乎在那里 是一个刷新问题。仅关闭/扩展节点将显示正确的 结果。我也没有在这个适合这个问题的论坛中找到任何答案。 也许有人可以尝试我的例子并告诉我问题出在哪里。 任何其他提示也非常感激。

问候,Marco

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());
    }
  }
}

感谢Ümit的解释。 我尝试了关闭重新打开的版本。 我用下面的方法替换了我的刷新方法。 添加工作但不删除。 整个话题都很奇怪。我很惊讶这些基本的 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());
            }
    }
}

3 个答案:

答案 0 :(得分:5)

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

有两种可能的解决方案:

  1. 为每个ListDataProviders保留一个参考,并在该列表上调用remove / add(尽管你这样做我认为这些项目并没有真正添加/删除)。
  2. 以编程方式关闭所有节点并重新打开它。
  3. 两者都是以某种方式实施的PITA。不幸的是,没有简单的方法。

答案 1 :(得分:0)

我只清除数据提供程序中维护的对象数组。我在onRangeChanged(final HasData<?> display)中执行此操作。我想我这里不使用ListDataProvider,而是使用扩展AbstractDataProvider<T>的内容。

要添加节点,请在onRangeChanged()方法中将其添加到列表中,然后调用updateRowData()。你也可以这样做删除。

答案 2 :(得分:0)

我想我可能已经舔过了这个问题......

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

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