GWT - Добавить и удалить узлы в celltree - PullRequest
8 голосов
/ 28 января 2012

Здесь у меня есть полный и очень простой пример для динамического добавления / удаления узлы в клеточном дереве. Мой пример не очень хорошо работает. Кажется там это проблема обновления Только закрытие / расширение узлов покажет правильное результат. Я также не нашел ответа на этом форуме, который подходит к этой проблеме. Может быть, кто-то может попробовать мой пример и сказать мне, где проблема. Любая другая подсказка также очень ценится.

Привет, Марко

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

Спасибо, Юмит, за ваше объяснение. Я попробовал закрытую версию. Я заменил мой метод обновления на методы ниже. Добавление работает, а удаление нет. Очень странная вся тема. Я очень удивлен, что эти основные функции на самом деле не поддерживаются 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 ]

5 голосов
/ 28 января 2012

Это как-то известная проблема с CellTree.
Причина проблемы обновления заключается в том, что в функции getNodeInfo() вы создаете новый экземпляр ListDataProvider для каждого уровня CellTree.
CellTree обновляется / обновляется только в том случае, если вы обновляете элементы в этом ListDataProvider. Я считаю, что ваши функции removeMenu () и addSubMenu () добавляют и удаляют элементы из исходного списка, хранящегося в вашем классе MyNode, но не будут обновлять список в соответствующих ListDataProviders (вы можете попробовать проверить это в режиме отладки). * Причина, по которой CellTree обновляется, когда вы закрываете -открытие узлов происходит потому, что при повторном открытии узлов снова вызывается getNodeInfo(), и вся структура CellTree будет построена снова (включая новое меню или без удаленного соответственно).

Существует два возможных решения:

  1. Сохраните ссылку для каждого из ListDataProviders где-нибудь и назовите команду «удалить / добавить» в этом списке (хотя вы делаете это, я предполагаю, что элементы там не добавляются / не удаляются).
  2. Программно закройте все узлы и снова откройте его.

И то, и другое - это как-то PITA для реализации. К сожалению, нет простого пути.

0 голосов
/ 20 октября 2013

Я думаю, что, возможно, подошел к проблеме ...

По сути, я расширил и подклассов многих частей CellTree и получил почти идеальный рабочий пример. Здесь слишком сложно документировать, но достаточно сказать, что решение включало использование класса узлов, где я хранил провайдера данных в каждом узле.

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

0 голосов
/ 19 марта 2012

Я просто очищаю массив объектов, хранящихся в моем поставщике данных. Я делаю это в onRangeChanged(final HasData<?> display). Я думаю, я не использую ListDataProvider здесь, я использую что-то расширяющее AbstractDataProvider<T>.

Чтобы добавить узел, добавьте его в свой список в методе onRangeChanged() и затем вызовите updateRowData(). Вы можете сделать это и для удаления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...