如何通过单击文本而不是图标来打开GWT CellTree节点

时间:2015-07-23 08:41:46

标签: java gwt

我正在使用javadoc中描述的GWT CellTree复杂示例。但要打开树节点,我必须单击节点左侧的小箭头。我想通过点击文本打开树。我搜索了一些帮助,发现我可以使用ClickableTextCell。真的说,我不明白从哪里开始。你能帮助我或提供其他解决方案吗?我希望该节点看起来像一个锚:当我在文本上鼠标时,光标变为指针,文本下划线。

public <T> NodeInfo<?> getNodeInfo(T value) {
      if (value == null) {
        ListDataProvider<Composer> dataProvider = new ListDataProvider<CellTreeExample2.Composer>(
            composers);
        Cell<Composer> cell = new AbstractCell<Composer>() {
          @Override
          public void render(Context context, Composer value, SafeHtmlBuilder sb) {
            if (value != null) {
              sb.appendEscaped(value.getName());
            }
          }
        };
        return new DefaultNodeInfo<Composer>(dataProvider, cell);
      } else if (value instanceof Composer) {
        ListDataProvider<Playlist> dataProvider = new ListDataProvider<Playlist>(
            ((Composer) value).getPlaylists());
        Cell<Playlist> cell = new AbstractCell<Playlist>() {
          @Override
          public void render(Context context, Playlist value, SafeHtmlBuilder sb) {
            if (value != null) {
              sb.appendEscaped(value.getName());
            }
          }
        };
        return new DefaultNodeInfo<Playlist>(dataProvider, cell);
      } else if (value instanceof Playlist) {
        ListDataProvider<String> dataProvider = new ListDataProvider<String>(
            ((Playlist) value).getSongs());
        return new DefaultNodeInfo<String>(dataProvider, new TextCell(),
            selectionModel, null);
      }

      return null;
    }
    public boolean isLeaf(Object value) {
      if (value instanceof String) {
        return true;
      }
      return false;
    }

3 个答案:

答案 0 :(得分:1)

您必须使用Cell来捕获单元格上的点击(如ClickableTextCell)。 在我的项目中,我只为树的第一层实现了这个系统:

Cell<String> nodeCell = new AbstractCell<String>("click", "keydown") {
    @Override
    public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event, ValueUpdater<String> valueUpdater) {
        String eventType = event.getType();
        // Special case the ENTER key for a unified user experience.
        if ("click".equals(eventType) || ("keydown".equals(eventType) && event.getKeyCode() == KeyCodes.KEY_ENTER)) {
            tree.getRootTreeNode().setChildOpen(context.getIndex(), !tree.getRootTreeNode().isChildOpen(context.getIndex()));
        }
    }

    @Override
    public void render(Cell.Context context, String value, SafeHtmlBuilder sb) {
        if (value != null) {
            sb.appendEscaped(value);
        }
    }
};

要打开更多关卡,必须在级联中使用setChildOpen:

tree.getRootTreeNode().setChildOpen(1, true).setChildOpen(1, true).setChildOpen(1, true);

答案 1 :(得分:1)

因为您可能不希望这些节点也可以选择,所以我会使用NoSelectionModel

每当您点击这些节点时,请在父setChildOpen()上调用TreeNode以切换其状态。要获取父TreeNode,请在祖父母setChildOpen(index, true)上使用TreeNode(递归到getRootTreeNode():因为您知道该节点已经加载并且已打开(您&#39} ;重新响应子节点上的事件),您可以确保setChildOpen将返回TreeNode而不是null。 最后,要让index传递给setChildOpen方法,只需在父&#34;域对象&#34;的子列表中使用indexOf()(即composers.indexOf(composer)composer.getPlaylists().indexOf(playlist)等。这假设您可以通过维护双向关系(playlist.getComposer().getPlaylists().indexOf(playlist))或通过构建子映射来轻松获取给定对象(给定播放列表的作曲家)的 →父母关系。

以下是您要从NoSelectionModel SelectionHandler拨打的一些构建基块:

void toggleComposerOpen(Composer composer) {
  int index = composers.indexOf(composer);
  TreeNode rootTreeNode = tree.getRootTreeNode();
  rootTreeNode.setChildOpen(index, !rootTreeNode.isChildOpen(index));
}

void togglePlaylistOpen(Playlist playlist) {
  Composer composer = playlist.getComposer();
  TreeNode composerTreeNode = getTreeNode(composer);
  int index = composer.getPlaylist().indexOf(playlist);
  composer.setChildOpen(index, !composer.isChildOpen(index));
}

private void TreeNode getTreeNode(Composer composer) {
  int index = composers.indexOf(composer);
  return tree.getRootTreeNode().setChildOpen(index, true);
}

答案 2 :(得分:1)

粗略的想法

使用SingleSelectionModel并将其传递到DefaultNodeInfo。添加onSelectionChanged处理程序,以便在调用它时:

  1. 获取所选项目
  2. 在关联的ListDataProvider中找到项目的索引,这将用于打开关联的子索引
  3. 使用CellTreeTreeNode打开关联的子索引
  4. 清除选择模型,以便在再次(连续)选择项目时,onSelectionChanged事件将再次触发。这将模拟切换。
  5. 示例:addSelectionChangeHandler

    添加选择更改处理程序。

    composerSingleSelectionModel = new SingleSelectionModel<Composer>(COMPOSER_KEY_PROVIDER);
    // ...
    composerSingleSelectionModel.addSelectionChangeHandler(
        new SelectionChangeEvent.Handler() {
            @Override
            public void onSelectionChange(SelectionChangeEvent event) {
                final TreeNode rootTreeNode = cellTree.getRootTreeNode();
                final Composer selectedComposer = composerSingleSelectionModel.getSelectedObject();
                if (selectedComposer == null) return;
                final int index = composerListDataProvider.getList().indexOf(selectedComposer);
                if (index < 0) return;
                final boolean isOpen = rootTreeNode.isChildOpen(index);
                rootTreeNode.setChildOpen(index, !isOpen);
                /* Clear what is currently selected, so that
                * onSelectionChange is fired again when the same item is
                * selected consecutively.
                */
                composerSingleSelectionModel.clear();
            }
        });
    

    示例:自定义TreeViewModel

    将作曲家选择模型传递给自定义TreeViewModel

    public class MusicTreeViewModel implements TreeViewModel {
        // Define constructor to pass in properties ...
    
        @Override
        public <T> NodeInfo<?> getNodeInfo(T value) {
            if (value == null) {
                return new DefaultNodeInfo<Composer>(composerListDataProvider, composerCell, composerSelectionModel, null);
            } else if (value instanceof Composer) {
                final Composer composer = (Composer) value;
                final Object composerKey = composerListDataProvider.getKey(composer);
                final ListDataProvider<Playlist> playlistListDataProvider = getPlaylistListDataProvider(composerKey);
                return new DefaultNodeInfo<Playlist>(playlistListDataProvider, playlistCell, playlistSelectionModel, null);
            } else {
                throw new IllegalArgumentException(
                    "Unsupported object type: " + value.getClass().getName());
            }
        }
    
        @Override
        public boolean isLeaf(Object value) {
            if (value instanceof Composer) {
                return ((Composer) value).getPlaylists().isEmpty();
            } else if (value instanceof Playlist) {
                return true;
            }
            return false;
        }
    }