GMF树形布局 2 实现展开/折叠

我的未来我决定 提交于 2020-04-07 12:10:23

这一篇博客在上一篇的基础上,实现展开/折叠功能。期待的最终效果是,双击某一Node,其后面的Node与连线都隐藏;再双击时显示回来。并且折叠之后,保存关闭,下次打开时还处于折叠状态,可以正确展开。

有一个细节应当注意,如下图:

比如折叠了节点1之后再折叠节点0,之后再展开节点0的时候,节点1应当还是处于折叠状态。

具体步骤如下:

1、为了实现这个展开/折叠操作,并且方便以后实现图标的更换,可以在节点的模型文件中添加一个布尔型的变量expanded,用于标识展开状态。可以在模型文件中修改,然后重新生成Model Code以及Edit Code,具体操作可以参考这里的步骤1、2。注意,将expanded的默认值设为true。

2、创建一个Command,用于实现折叠或者展开。先在diagram工程下的src目录下新建一个package,名为org.eclipse.gmf.examples.mindmap.diagram.edit.commands.custom,在其中新建一个class文件,名为ExpandOrCollapseCommand,继承自RecordingCommand。

3、ExpandOrCollapseCommand的构造函数如下,获取

public ExpandOrCollapseCommand(
        TransactionalEditingDomain transactionalEditingDomain,
        TopicEditPart topicEditPart) {
    super(transactionalEditingDomain);
    this.sourceEdgeList = ((View) topicEditPart.getModel()).getSourceEdges();
    this.setLabel("Expand Or Collapse");
    this.topicModel = (Topic) ((View) topicEditPart.getModel()).getElement();
    this.isExpanded = topicModel.isExpanded();
    this.topicEditPart = topicEditPart;
}

4、重写doExecute()方法:

@Override
protected void doExecute() {
    if (this.sourceEdgeList.size() > 0) {
        this.topicModel.setExpanded(!this.isExpanded);
        this.doExpandOrCollapse(this.topicModel, this.sourceEdgeList, !this.isExpanded);
    }
}
5、最关键的doExpandOrCollapse方法代码:
/**
 * 执行展开或者折叠功能,并且将子节点的元素也要相应地展开或者折叠
 */
private void doExpandOrCollapse(Topic model, List edgeList, boolean visible) {
    Iterator<ConnectorImpl> iter = edgeList.iterator();
    while (iter.hasNext()) {
        Edge conn = iter.next();
        conn.getTarget().setVisible(visible);
        Topic targetModel = (Topic) conn.getTarget().getElement();
        List targetSourceEdgeList = conn.getTarget().getSourceEdges();
        if (this.isExpanded) {
            // 如果将要折叠,则应将子节点全部隐藏
            doExpandOrCollapse(targetModel, targetSourceEdgeList, false);
        } else if (!this.isExpanded && targetModel.isExpanded()) {
            // 如果将要展开,则应将子节点中,在折叠之前处于展开状态的展开
            doExpandOrCollapse(targetModel, targetSourceEdgeList, true);
        }
    }
}

6、接下来则要使用这个命令。由于是双击,所以先要捕获对节点的双击事件。在TopicEditPart类中重写超类中的performRequest(Request request)方法:

/**
 * 捕获各种事件,如双击
 */
@Override
public void performRequest(Request request) {
    if (request.getType() == (RequestConstants.REQ_OPEN)) {
        // 双击时展开或者隐藏后面的节点
        Topic model = (Topic) ((View) this.getModel()).getElement();
        TransactionalEditingDomain domain = TransactionUtil
                .getEditingDomain(this.getModel());
        ExpandOrCollapseCommand command = new ExpandOrCollapseCommand(
                domain, this);
        domain.getCommandStack().execute(command);
    }
    super.performRequest(request);
}

7、现在运行,会发现已经可以展开/折叠了,但是,存在一个问题:当把某一节点折叠,保存关闭后,再打开图,然后再展开这个节点,与它直接相连的节点并不会马上显示,需要保存、关闭之后再打开才会显示,如下图:


8、解决上面的问题,需要在TopicEditPart中重写getModelSourceConnections()方法。如果在超类ShapeNodeEditPart中查看原始的getModelSourceConnections()方法,最终找到ViewUtil中的getSourceConnectionsConnectingVisibleViews(View view)方法,会发现其中有一个判断:

if (edge.isVisible() && isVisible(target)){
    sourceConnections.add(edge);
}

而我们是要得到所有的edge,不管是否可见。我们虽然没有手动调用getModelSourceConnections(),但是在内部它是被调用的,所以TopicEditPart中重写getModelSourceConnections()方法如下:

/**
 * 重写getModelSourceConnections()方法
 */
@Override
protected List getModelSourceConnections() {
    View view = (View) this.getModel();
    if (!view.eIsSet(NotationPackage.Literals.VIEW__SOURCE_EDGES))
        return Collections.EMPTY_LIST;
    return view.getSourceEdges();
}

9、此时再运行,则不会出现上述问题。

最终代码在这里

双子座@开源中国


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!