之前有一篇文件介绍怎么实现GEF Editor中的图元的渐近、动态变化过程的显示技巧。
在GEF的Flow例子里,已经提供了另一种实现动态变化的方式,这个实现方法主要由以下三部分组成:
- 需要有一个辅助类,用于记录初始和终态,并计算渐近过程
- 需要自定义一个布局类,借助上面的辅助类来给出当前布局
- 需要窗口类控制器需要监听状态变化,以决定什么时候开始激活动态过程
- 每个可能属于变化集的对象都需要提供一个方法,用于把自己加入到这个变化集中。
下面一部分一部分的介绍。
首先第一个部分,就是辅助类的实现,不过我也没写过自己的实现方式,暂且先以flow中的类作例子,见附件GraphAnimation.zip.
第二部分也是一个类实现,简单如下:
class GraphLayoutManager extends AbstractLayout {
private NumaDiagramNodePart diagram;
GraphLayoutManager(NumaDiagramNodePart diagram) {
this.diagram = diagram;
}
protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) {
container.validate();
List children = container.getChildren();
Rectangle result =
new Rectangle().setLocation(container.getClientArea().getLocation());
for (int i = 0; i < children.size(); i++)
result.union(((IFigure)children.get(i)).getBounds());
result.resize(container.getInsets().getWidth(), container.getInsets().getHeight());
return result.getSize();
}
public void layout(IFigure container) {
GraphAnimation.recordInitialState(container);
if (GraphAnimation.playbackState(container))
return;
CompoundDirectedGraph graph = new CompoundDirectedGraph();
graph.setDirection(PositionConstants.EAST);
Map partsToNodes = new HashMap();
diagram.contributeNodesToGraph(graph, partsToNodes);
diagram.contributeEdgesToGraph(graph, partsToNodes);
new CompoundDirectedGraphLayout().visit(graph);
diagram.applyGraphResults(graph, partsToNodes);
}
}
这里借助了两个对象来实现过程:CompoundDirectedGraph和CompoundDirectedGraphLayout。
第三,监听状态变化,这部分主要就是通过在容器类中增加Command变化监听来实现,例如:
CommandStackListener stackListener = new CommandStackListener() {
public void commandStackChanged(EventObject event) {
if (!GraphAnimation.captureLayout(getFigure()))
return;
while (GraphAnimation.step())
getFigure().getUpdateManager().performUpdate();
GraphAnimation.end();
}
};
public void activate() {
super.activate();
getViewer().getEditDomain().getCommandStack().addCommandStackListener(
stackListener);
}
public void deactivate() {
getViewer().getEditDomain().getCommandStack()
.removeCommandStackListener(stackListener);
super.deactivate();
}
最后一部分,也就是参与的过程,虽然上面我们已经定义好了整个辅助过程,但是具体在这一过程中有哪些对象会参与,怎么参与,需要我们自己实现,例如A是容器对象,里面有B和C对象,且B和C之间有一条连线,那么一般来说,一旦有变化,那么B,C和他们连线都需要处理。
对于一个结点对象,处理过程通常如:
public void applyGraphResults(CompoundDirectedGraph graph, Map map) {
for (int i = 0; i < getChildren().size(); i++) {
NumaNodePart node = (NumaNodePart) getChildren().get(i);
Dimension dimension = node.getFigure().getPreferredSize(-1, -1);
Node n = (Node) map.get(node);
node.getFigure().setBounds(
new Rectangle(n.x, n.y, n.width, dimension.height));
applyEdgesResults(node, graph, map);
}
}
public void contributeNodesToGraph(CompoundDirectedGraph graph, Map map) {
GraphAnimation.recordInitialState(getContentPane());
for (int i = 0; i < getChildren().size(); i++) {
NumaNodePart node = (NumaNodePart) getChildren().get(i);
Node n = new Node(node);
n.width = node.getFigure().getPreferredSize().width;
n.height = node.getFigure().getPreferredSize().height;
n.setPadding(new Insets(10, 8, 30, 12));
map.put(node, n);
graph.nodes.add(n);
}
}
public void contributeEdgesToGraph(CompoundDirectedGraph graph, Map map) {
for (int i = 0; i < getChildren().size(); i++) {
NumaNodePart node = (NumaNodePart) children.get(i);
List outgoing = node.getSourceConnections();
for (int j = 0; j < outgoing.size(); j++) {
NodeRelationPart conn = (NodeRelationPart) outgoing.get(j);
conn.contributeToGraph(graph, map);
}
}
}
public void applyEdgesResults(NumaNodePart node,
CompoundDirectedGraph graph, Map map) {
List outgoing = node.getSourceConnections();
for (int j = 0; j < outgoing.size(); j++) {
NodeRelationPart conn = (NodeRelationPart) outgoing.get(j);
conn.applyGraphResults(graph, map);
}
}
对于连线,因为要处理他们的Bend点,通常如下:
protected void applyGraphResults(CompoundDirectedGraph graph, Map map) {
Edge e = (Edge)map.get(this);
NodeList nodes = e.vNodes;
PolylineConnection conn = (PolylineConnection)getConnectionFigure();
// conn.setTargetDecoration(new PolygonDecoration());
if (nodes != null) {
List bends = new ArrayList();
for (int i = 0; i < nodes.size(); i++) {
Node vn = nodes.getNode(i);
int x = vn.x;
int y = vn.y;
if (e.isFeedback()) {
bends.add(new AbsoluteBendpoint(x, y + vn.height));
bends.add(new AbsoluteBendpoint(x, y));
} else {
bends.add(new AbsoluteBendpoint(x, y));
bends.add(new AbsoluteBendpoint(x, y + vn.height));
}
}
conn.setRoutingConstraint(bends);
} else {
conn.setRoutingConstraint(Collections.EMPTY_LIST);
}
}
public void contributeToGraph(CompoundDirectedGraph graph, Map map) {
GraphAnimation.recordInitialState(getConnectionFigure());
Node source = (Node)map.get(getSource());
Node target = (Node)map.get(getTarget());
Edge e = new Edge(this, source, target);
e.weight = 2;
graph.edges.add(e);
map.put(this, e);
}
并且,在他们重连的时候需要处理:
figure.setConnectionRouter(new BendpointConnectionRouter(){
public void route(Connection conn) {
GraphAnimation.recordInitialState(conn);
if (!GraphAnimation.playbackState(conn))
super.route(conn);
}
});