【问题标题】:GWT - Add and remove nodes in celltreeGWT - 在 celltree 中添加和删除节点
【发布时间】:2012-01-28 10:50:54
【问题描述】:

这里我有一个完整且非常简单的示例来动态添加/删除 节点到细胞树。我的例子不是很好。好像有 是刷新问题。只有关闭/展开节点才会显示正确 结果。我在这个论坛上也没有找到任何适合这个问题的答案。 也许有人可以试试我的例子并告诉我问题出在哪里。 任何其他提示也非常感谢。

你好,马可

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

【问题讨论】:

标签: gwt add


【解决方案1】:

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

有两种可能的解决方案:

  1. 在某处保留每个 ListDataProviders 的引用,并在该列表上调用 remove/add(尽管您这样做,但我认为这些项目并未真正添加/删除)。
  2. 以编程方式关闭所有节点并重新打开它。

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

【讨论】:

  • 感谢 Ümit 的解释。我尝试了关闭重新打开的版本。添加有效,但删除无效。对于您建议的解决方案之一,您有完整的工作示例吗?
  • 明天或后天我会发布关闭重开代码
  • 嗨Ümit,你有例子吗?我仍然没有找到解决方案。
  • 有人干净地解决了这个问题吗?令人沮丧的是,这已按照 GWT 问题列表中的设计关闭 - code.google.com/p/google-web-toolkit/issues/detail?id=7160
  • @SSR 不幸的是没有。我已经从 CellTree 切换到了普通的 Tree 小部件(因为我没有很多节点要显示)。我认为可能必须扩展CellTree 类来实现此功能(甚至可能为 GWT 本身提供补丁)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    我想我可能已经解决了问题......

    基本上我已经扩展和继承了 CellTree 的许多部分,并获得了一个几乎完美的工作示例。在这里记录太复杂,但足以说明解决方案涉及使用节点类,我将数据提供者存储在每个节点中。

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

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
    • 很公平,但如果您花时间真正查看答案,则不太实用。解决方案不够简单,无法包含在此处是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 2012-07-21
    • 1970-01-01
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多