GEF的图形渐变方法
http://www.4ucode.com/Study/Topic/1967675(引用)
在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); } })