YON Blog

Intellij Plugin - SimpleTree 使用

IntelliJ IDE 中交互展示形式里大量使用了树形列表。开发插件的时候可以使用传统的 Swing 的 JTree 组件来构建树形列表,但是使用 JTree 需要我们自己做很多额外的工作来实现一些基本的功能,例如,列表为空时的提示文案、节点双击的回调、右键菜单等等。官方文档里推荐的是使用 IntelliJ 自己封装的 Tree 对象来替代 JTree [1],但是 Tree 也只是解决了部分问题,一些在 IDE 里树形列表里常见的功能还要自己配置。翻阅社区版 IDEA 的源码,可以发现官方自带的插件里使用的是 SimpleTree 组件,在 Tree 基础上进一步包装里常见的功能,真正做到开箱即用。
SimpleTree 可以搭配传统的 DefaultTreeModel 来使用,但这样我们需要非常过程化的使用 DefaultMutableTreeNode 来构建整个树,意思就是,我们在构建树的时候就要知道树的根节点是什么,根节点的子节点是哪些,子节点的子节点是哪些。更好的方式是我们构建树的时候只需要知道他的根节点是什么,具体的根节点的子节点有哪些不应该我们外部去感知,而是根节点自己去决定。为了更优雅的构建树,SimpleTree 可以搭配 StructureTreeModel 来使用:

StructureTreeModel<SimpleTreeStructure> treeModel = new StructureTreeModel<>(new SimpleTreeStructure.Impl(new GroupNode(group)), this);
SimpleTree tree = new SimpleTree(new AsyncTreeModel(treeModel, this));
// 隐藏根节点
tree.setRootVisible(false);
  • StructureTreeModel 的构建依赖 AbstractTreeStructure 对象,我们可以直接用自带的 SimpleTreeStructure.Impl 对象。SimpleTreeStructure.Impl 需要一个 SimpleNode 作为根节点,这里的 GroupNode 就是我们自定义的 SimpleNode,他会在 getChildren() 方法中返回他自己的子节点,不用我们外部关心
  • StructureTreeModel 的构建还需要一个 Disposable 对象,上面例子里的 this 实现了该接口
  • StructureTreeModel 要给 SimpleTree 使用最好再封装一层 AsyncTreeModel,这样构建树时我们不用关心当前构建树的线程是否符合要求
  • 常见的 Tree/JTree 对象可做的配置都可以使用,上面例子里是把根节点隐藏了
  • 注意,SimpleTree 自己已经配置了 TreeSpeedSearch,所以外面不能再自己配置,否则 TreeSpeedSearch 会工作正常

开发 IntelliJ 插件,一个比较好的方式就是看看官方的一些插件是怎么实现的,很多功能其实都已经封装好了。官方插件的源码可以在 Github 上查看 [2],常见的插件如 Gradle、Maven、Git 的实现都在仓库的 plugins 目录里。提示一点,Git 插件的实现是基于扩展点的,一些核心的功能是在 platform/vcs-impl 里实现的。
[1] List and Tree Controls
[2] https://github.com/JetBrains/intellij-community