2012-01-28 16 views
8

Aquí tengo un ejemplo completo y muy fácil de añadir dinámicamente/eliminar nodos a un celltree. Mi ejemplo no está funcionando muy bien. Parece que es un problema de actualización. Solo al cerrar/expandir los nodos se mostrará el resultado correcto de . Tampoco encontré ninguna respuesta en este foro que se ajuste a este problema. Tal vez alguien pueda probar mi ejemplo y decirme dónde está el problema. Cualquier otra sugerencia también es muy apreciada.GWT - Añadir y eliminar nodos en celltree

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

Gracias Ümit por su explicación. He intentado la versión de abrir de nuevo. He reemplazado mi método de actualización con los métodos a continuación. Agregar está funcionando pero no elimina. Muy extraño todo el tema. Me sorprende mucho que estas funciones básicas realmente no sean compatibles con GWT. ¿Alguien puede darme más ayuda para ejecutar un ejemplo real de trabajo.

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

Aquí mi tercer intento: De esta manera es recomendado por GWT-commiter. Por favor, véase la siguiente cuestión: http://code.google.com/p/google-web-toolkit/issues/detail?id=7160

Estado actual: * La adición es posible * Extracción es posible si no fuera último hijo!

Así, último punto abierto, refrescar el árbol si el último hijo abierta!

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

¿Alguien se ha salido con la suya limpiamente? Frustrante, esto está cerrado como está diseñado en GWT issuelist - http://code.google.com/p/google-web-toolkit/issues/detail?id=7160 – SSR

Respuesta

5

Esto es de alguna manera un problema conocido con CellTree.
La razón para el problema de actualización es que en la función getNodeInfo() se crea una nueva instancia para cada ListDataProvider nivel CellTree.
La única CellTree actualizaciones/refresca si actualiza los elementos de esa ListDataProvider. que creen que sus funciones removeMenu() y addSubmenu() añadir y quitar elementos de la lista original almacenado en su clase MyNode pero no actualizará la lista de los ListDataProviders correspondientes (se puede tratar de comprobar que, en el modo de depuración).
La razón por la que el CellTree se actualiza cuando cierra y vuelve -abierta los nodos es porque cuando vuelve a abrir los nodos se llama nuevamente al getNodeInfo() y toda la estructura de CellTree se construirá de nuevo (incluyendo el nuevo menú o sin el eliminado uno respectivamente).

Hay dos soluciones posibles:

  1. mantener una referencia para cada uno de los ListDataProviders algún lugar y llamar a eliminar/añadir en esa lista (aunque se hace eso supongo que los artículos no se agregan realmente/removidos existe)
  2. Programemente cierre todos los nodos y vuelva a abrirlo.

Ambos son de alguna manera un PITA para implementar. Lamentablemente, no hay una manera fácil de evitarlo.

+0

Gracias Ümit por su explicación. Intenté la versión de abrir de nuevo. Agregar está funcionando pero eliminando no. ¿Tiene un ejemplo completo de trabajo para una de sus soluciones sugeridas? – user1165474

+0

Voy a publicar un código de reabrir mañana o pasado mañana –

+0

Hola, ¿tienes un ejemplo? Todavía no he encontrado una solución para eso. – user1165474

0

acabo de borrar el conjunto de objetos que se mantienen en mi proveedor de datos. Hago esto en onRangeChanged(final HasData<?> display).Supongo que no uso un ListDataProvider aquí, utilizo algo que se extiende AbstractDataProvider<T> en su lugar.

Para agregar el nodo agréguelo a su lista dentro del método onRangeChanged() y luego llame al updateRowData(). Usted puede hacer esto para una eliminación también.

0

Creo que puede haber solucionado el problema ...

Esencialmente hemos ampliado y subclases muchas partes del CellTree y han obtenido un ejemplo de trabajo casi perfecto. Demasiado complejo para documentarlo aquí, pero basta con decir que la solución implicó usar una clase de nodo donde almacené el proveedor de datos dentro de cada nodo.

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

+0

Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcione el enlace para referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. – chris

+0

Lo suficiente, pero no es realmente práctico si se tomó el tiempo para ver realmente la respuesta. La solución no es algo tan simple de incluir aquí, ¿sí? – gslender