的就是让它们根据节点的当前状态返回正确的连接,所以作为容器 的SubjectPart要做这样的修改:
protected List getModelSourceConnections() {
if (!getSubject().isCollapsed()) {
return getSubject().getOutgoingConnections();
} else {
List l = new ArrayList();
l.addAll(getSubject().getOutgoingConnections());
for (Iterator iter = getSubject().getAttributes().iterator(); iter.hasNext();) {
Attribute attribute = (Attribute) iter.next();
l.addAll(attribute.getOutgoingConnections());
}
return l;
}
}
也就是说,当处于展开状态时,正常返回自己作为起点的那些连接;否则除了这些连接以 外,还要包括子图形对应的那些连接。作为子图形的AttributePart也要修改,因为当所在容 器折叠后,它们对应的连接也要隐藏,修改后的代码如下所示:
protected List getModelSourceConnections() {
Attribute attribute = (Attribute) getModel();
Subject subject = (Subject) ((SubjectPart) getParent()).getModel();
if (!subject.isCollapsed()) {
return attribute.getOutgoingConnections();
} else {
return Collections.EMPTY_LIST;
}
} 由于getModelTargetConnections()的代码和getModelSourceConnections()非常类 似,这里就不列出其内容了。在一般情况下,我们只让一个EditPart监听一个模型的变化, 但是请记住,GEF框架并没有规定EditPart与被监听的模型一一对应(实际上GEF中的很多设 计就是为了减少对开发人员的限制),因此在必要时我们大可以根据自己的需要灵活运用。 在实现展开/折叠功能时,子元素的EditPart应该能够监听所在容器的状态变化,当 collapsed值改变时更新与子图形相关的连接线(若不进行更新则这些连接线会变成"无头线" )。让子元素EditPart监听容器模型的变化很简单,只要在AttributePart的activate()里把 自己作为监听器加到容器模型的监听器列表即可,注意别忘记在deactivate()里注销掉,而 propertyChange()方法里是事件发生时的处理,代码如下:
public void activate() {
super.activate();
((Attribute) getModel()).addPropertyChangeListener(this);
((Subject) getParent().getModel()).addPropertyChangeListener(this);
}
public void deactivate() {
super.deactivate();
((Attribute) getModel()).removePropertyChangeListener(this);
((Subject) getParent().getModel()).removePropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(Subject.PROP_COLLAPSED)) {
refreshSourceConnections();
refreshTargetConnections();
}
super.propertyChange(evt);
}
这样,基本上就实现了容器的展开/折叠功能,之所以说"基本上",是因为我没有做仔细 的测试(时间关系),目前的代码有可能会存在问题,特别是在Undo/Redo以及多重选择这些 情况下;另外,这种方法只适用于容器里的子元素不是容器的情况,如果有多层的容器关系 ,则每一层都要做类似的处理才可以。
本文配套源码 |