一、带箭头的连接线
PolylineConnection connection = super.createFigure() ;
PolygonDecoration decoration = new PolygonDecoration();
connection.setTargetDecoration(decoration);
return connection;
}
ArrowConnectionEditPart editPart = new ArrowConnectionEditPart();
editPart.setModel(model);
return editPart;
}
"plain", "this is arrow connection", new SimpleFactory(
ArrowConnectionModel.class), Activator
.getImageDescriptor("icons/arrowLine.gif"), Activator
.getImageDescriptor("icons/arrowLine.gif"));
selectionGroup.add(arrowConnection);
图一
二、增加连接线的路由点
现在,我们所有的连线都是直来直去的,不会打弯。这样的一个坏处就是,线会在图上画过。所以为了能更改连接线的路径,我们需要让连接线支持路由点。首先先不考虑其他的,我们单纯创建一个带路由点的线。
背景知识
要想让线支持路由,我们就需要为PolylineConnection设置新的ConnectionRouter对象,因为缺省的是ConnectionRouter.NULL;我们可以找一个ConnectionRouter的子类。这里我们设置为:BendpointConnectionRouter。
所以下面要怎么支持路由点,就由这个BendpointConnectionRouter说了算了。我们看一下BendpointConnectionRouter的源码,看看它是怎么取得和设置路由点的:
首先在方法:setConstraint(Connection connection, Object constraint)的实现里,以connection为键值,将所有这个connection的constraint放到一个Map里去了。
然后看方法:route(Connection conn);这就是用来具体设置路由点的。可以看到它先以connection为键,从Map里取出所有的constraint,然后把这个constraint强制为一个List,最后从List里的取出的对象再强制为一个BendPoint对象。
从上面,我们基础可以猜测,在以BendpointConnectionRouter为连接路由的情况下,我们应该怎么设置路由点了。如下:
List list = new ArrayList();
list.add(new AbsoluteBendpoint(10,30));
connection.setRoutingConstraint(list);
其中,AbsoluteBendpoint为BendPoint类的一个子类。
实现
由了上面的背景知识,要实现就不难了。不过首先我们修改一下模型。为了记录连接线的路由点,我们需要加一个属性。这里我们都以AbstractConnectionModel来做,因为我们可以假设所有的线都需要支持路由点。我假设我们都已经较熟练了,所以这次我们写得全面一些:
首先我们让我们AbstractConnectionModel继承AbstractModel,因为我们要涉及到了事件通知了。
其次,在AbstractConnectionModel里追加以下内容用以支持增加、移除和移动路由点:
public static final String P_CONSTRAINT = "p_constraint";
private List<Bendpoint> constraints = new ArrayList<Bendpoint>();
public List<Bendpoint> getConstraints() {
return constraints;
}
public void addConstraint(int index, Bendpoint bendpoint) {
if (!constraints.contains(bendpoint)) {
constraints.add(index, bendpoint);
firePropertyChange(P_CONSTRAINT, null, bendpoint);
}
}
public void setConstraint(int index, Bendpoint bendpoint) {
if (!constraints.contains(bendpoint)) {
constraints.set(index, bendpoint);
firePropertyChange(P_CONSTRAINT, null, bendpoint);
}
}
public void removeConstraint(int index) {
Bendpoint bendpoint = constraints.get(index);
constraints.remove(index);
firePropertyChange(P_CONSTRAINT, bendpoint, null);
}
有一点需要注意的:为了保证操作后的路由点显示正确,我们在操作时需要保证操作结点的顺序。所以看上面三个处理方法中,都是基于index来实现的。
接下来还是实现Policy和Command。这下我们应该可以很快就找到我们的Policy了:BendpointEditPolicy。而且我们也应该知道它应该安在哪了:AbstractConnectionModelEditPart。如下:
installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE, new ConnectionBendpointEditPolicy());
最后就是实现Policy里的三个命令。这里我就不一一写了。样子都差不多。就举一个增加的例子:
public class CreateBendPointCommand extends Command {
private AbstractConnectionModel model;
private AbsoluteBendpoint point;
private int index;
public CreateBendPointCommand(AbstractConnectionModel model, Point point, int index) {
super();
this.model = model;
this.point = new AbsoluteBendpoint(point);
this.index = index;
}
@Override
public void execute() {
model.addConstraint(index,point);
}
@Override
public void undo() {
model.removeConstraint(index);
}
}
最后完成我们的Policy:
@Override
protected Command getCreateBendpointCommand(BendpointRequest request) {
CreateBendPointCommand command = new CreateBendPointCommand(
(AbstractConnectionModel) request.getSource().getModel(),request.getLocation(),
request.getIndex());
return command;
}
@Override
protected Command getDeleteBendpointCommand(BendpointRequest request) {
RemoveBendPointCommand command = new RemoveBendPointCommand(
(AbstractConnectionModel) request.getSource().getModel(),
request.getLocation(),request.getIndex());
return command;
}
@Override
protected Command getMoveBendpointCommand(BendpointRequest request) {
MoveBendPointCommand command = new MoveBendPointCommand(
(AbstractConnectionModel) request.getSource().getModel(),
request.getIndex(), request.getLocation());
return command;
}
按照背景知识里的说法,为了支持路由,我们需要给连接线设置一个ConnectionRouter。所以个性createFigure()方法如下:
@Override
protected IFigure createFigure() {
PolylineConnection connection = new PolylineConnection();
connection.setConnectionRouter(new BendpointConnectionRouter());
return connection;
}
好,我们可以试一下现在的效果: 已经可以用鼠标拖出一个一个的路由点了。只是放开后又恢复了。这次好像我们已经写了监听啊。咋回事呢?玩我的吧?发出事件写了是没错的,不过还没完成事件监听和处理。下面我们就要完成我们的事件处理。
修改AbstractConnectionModelEditPart,让它实现PropertyChangeListener监听,然后在propertyChange()方法可以这样写:
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals(AbstractConnectionModel.P_CONSTRAINT)){
refreshConnectionRoutes();
}
}
注意,这个refreshConnectionRoutes()是我自己写的。editPart本身并不带。好了,现在的任务就是怎么完成这个方法了。终于到最后一步了,死了也值了,哈哈哈哈。
我是这样完成的:
private void refreshConnectionRoutes() {
List<Bendpoint> constraints = ((AbstractConnectionModel)getModel()).getConstraints();
((PolylineConnection)getFigure()).setRoutingConstraint(constraints);
}
再试一下!!!!!唉呀,怎么回来啊,还是没出来。跟踪一下:它根本就没进我的propertyChange()方法里来嘛。知道了,是因为我没有把监听加上。在AbstractConnectionModelEditPart,追加以下内容即可(老东西,照着写就行了):
@Override
public void activate() {
super.activate();
((AbstractConnectionModel)getModel()).addPropertyChangeListener(this);
}
@Override
public void deactivate() {
((AbstractConnectionModel)getModel()).removePropertyChangeListener(this);
super.deactivate();
}
好了,这下肯定会出来了。我保证!!!效果图如下: