随着时间的推移,任务已经完成的差不多了,虽然不是一帆风顺但是遇到的问题还是逐一解决了。因为前一段时间春节放假,年终晚会,等等原因,所以一直没有写开发日志。先说一个题外话就是关于过节,我个人十分的讨厌过节,因为它会影响我的正常生活,比如我正常的生活要写开发日志,要深入的研究gef,要看书但是都因为过节而搁浅了。春节前2天,公司里的人就只剩十几个人了,根本没有心情工作。当然了我说的是长假。2,3天的节假日还是可以的。
废话少说,进入主题。
关于part,policy和command对于初学者来说很头疼,不知道应该在什么样的part中添加什么样的policy是我刚刚开始gef的时候最困惑的事情。而网上说的不是很详细,网友们给我的大夫就只是:看看源码就清楚了。当时对于初学之来讲看懂源码真的是太难了,因为gef的mvc编程模式虽然在编程的时候很好用,但是在看源码的时候没有一定的积累很难看明白。现在我就给大家分析分析分析。
以前看到过一个英文的关于policy的用途的说明,说的很明白,但是找不到了,我就跟大家自述一下:检查接收到的请求(request)是否有相应的操作流程。说白了就是说例如我们对我们已经存在的控件进行了双击,而系统会捕获到这个事件,并发送到part一个位置,在这个位置里part检查是否有相应的处理事件的操作(command),如果有就执行这个操作,如果没有的话就销毁这个请求(request)。
在AbstractEditPart中源码是这样的:
public Command getCommand(Request request) {
Command command = null;
EditPolicyIterator i = getEditPolicyIterator();
while (i.hasNext()) {
if (command != null)
command = command.chain(i.next().getCommand(request));
else
command = i.next().getCommand(request);
}
return command;
}
我们的part都要继承AbstractEditPart。而系统把接收到的事件传到这个方法中,然后getCommand方法会遍历所有的安装的policy,并获取并返回command。当然了,如果command为空就撤销request,如果不为空就执行。那么policy是在那里得到的呢?
@Override
protected void createEditPolicies() {
super.createEditPolicies();
installEditPolicy("myPolicy", new MyAbstractEditPolicy());
}
在我们新建part的时候都要重写这个方法,而这个installEditPolicy这个方法就把我们的policy安装了进去。所以getEditPolicyIterator就是获得的我们所安装进的policy。然后调用policy的getCommand方法来获取到相应的command。
下面我以拖拽为例给大家举例讲解一下。
首先我们要在我们的part上面添加policy,而这个policy应该添加到那里呢?是应该添加到容器里面呢还是应该添加到容器里的节点上呢?这要看我们具体的做法。我们先分析一下我们要对拖拽进行操作,而最终的做法就是就是改变节点里面的constraint(约束:位置,大小)属性然后再刷新。而要修改的话我们就需要model。
在partfactory中我们通常的做法是这样的
@Override
public EditPart createEditPart(EditPart context, Object model) {
MyEditPartWithListener part = getPartFromElement(model);
part.setModel(model);
return part;
}
就是说在创建part的时候就把model注入了进去,所以要想获取到model的话就要先得到part。而installEditPolicy的做法是这样的
......
if (editPolicy != null) {
editPolicy.setHost(this);
if (isActive())
editPolicy.activate();
}
就是说吧part注入到了policy里面。所以说白了就是policy按在了那个part上,就能获取到那个part,就能获取到相应的model。那么我们的操作时要更改model里面的constraint属性所以要获取节点的model,所以要获取节点的part所以我们要把这个policy安装到节点上面。当然了,安装在节点里肯定没有问题,但是我们再想想,如果我们想同时修改多个节点的位置怎么办!在仅有的设计里是实现不了的。gef中把这种设计放到了request里面我们看看需要的ChangeBoundsRequest。在它的父类里有一个list装的是EditPart
而我们再看看我们的policy的父类。刚刚说了,在AbstractEditPart中我们会遍历安装了的policy,然后调用policy的getCommand方法。那我们就看看XYLayoutEditPolicy的getCommand方法:通过调用,我们看一看到:
protected Command getChangeConstraintCommand(ChangeBoundsRequest request) {
CompoundCommand resize = new CompoundCommand();
Command c;
GraphicalEditPart child;
List children = request.getEditParts();
for (int i = 0; i < children.size(); i++) {
child = (GraphicalEditPart) children.get(i);
c = createChangeConstraintCommand(
request,
child,
translateToModelConstraint(getConstraintFor(request, child)));
resize.add(c);
}
return resize.unwrap();
}
正是他调用createChangeConstraintCommand(ChangeBoundsRequest request, EditPart child, Object constraint),然后在调用我们需要重写的createChangeConstraintCommand(EditPart child,Object constraint),这里面的part是来自于request的,并不是来自于policy。所以这样,每一个被选中的part都可以得到相应的修改。所以,这个policy安装在节点里或者容器里都可以。如果按在节点里的话那么每一种节点都要安装一遍,所以我们把它安装在容器里面,这样少一些代码。
首先我们继承XYLayoutEditPolicy并重写createChangeConstraintCommand方法,至于command怎么去写不是今天的重点,就不说了。然后把我们的XYLayoutEditPolicy安装到容器的part中就可以了。
至于其他的policy也是同样的道理。大家自己发挥吧。