一. 目标
- 能够选中Table,移动Table的位置,调整Table的大小。
- 可以支持撤销Undo和重做Redo。
二. 给DataBase书写XYLayoutEditPolicy
书写一个DataBaseXYLayoutEditPolicy 类继承与XYLayoutEditPolicy
public class DataBaseXYLayoutEditPolicy extends XYLayoutEditPolicy {
@Override
protected Command createChangeConstraintCommand(EditPart child, Object constraint) {
return null;
}
@Override
protected Command getCreateCommand(CreateRequest request) {
return null;
}
}
将其注册于DataBaseEditPart 上
@Override
protected void createEditPolicies() {
installEditPolicy(EditPolicy.LAYOUT_ROLE, new DataBaseXYLayoutEditPolicy());
}
启动后查看效果:
好了,就这么简单,已经可以选中Table了,选中后会出现边框,而且边框还有8个可用于调整大小的瞄点出现。
问题一: 为什么为了操作Table,而去给DataBase注册LayoutEditPolicy呢?
这是由于LayoutEditPolicy是用于对它上面的子EditPart而言的,这就SWT中给Composite设置GridLayout或FillLayout,具体怎么布局也是对于Composite上的子控件而言的。
问题二: 为什么注册了LayoutEditPolicy就会有选择框呢?
关心的话,可以去看ConstrainedLayoutEditPolicy.createChildEditPolicy的具体方法。
三. 书写Table执行调整大小的Command
public class TableChangeConstraitCommand extends Command {
private TableModel table;
private Rectangle oldRect;
private Rectangle newRect;
public TableChangConstraitCommand(TableModel table, Rectangle newRect) {
this.table = table;
this.newRect = newRect;
}
@Override
public void execute() {
oldRect = new Rectangle(table.getX(), table.getY(), table.getW(), table.getH());
table.setXYWH(newRect.x, newRect.y, newRect.width, newRect.height);
}
@Override
public void undo() {
table.setXYWH(oldRect.x, oldRect.y, oldRect.width, oldRect.height);
}
}
Command 用于具体执行对模型的修改:
- execute() 执行操作,在这里就是执行大小或位置调整,并保存旧的现场。
- undo() 撤销操作,其实就是从前面保存的现场,恢复到原来的大小和位置。
- redo() 重新执行 (如果不覆盖,其实就是执行execute方法)
这就是设计模型里面的Command模式,Command对象在被执行后,会保存在EditDomain 的CommandStack 中,用以支持Ctrl+Z的undo撤销操作,或者Ctry+Y的redo重新执行。
四. 改写DataBase的XYLayoutEditPolicy,支持大小调整
public class DataBaseXYLayoutEditPolicy extends XYLayoutEditPolicy {
@Override
protected Command createChangeConstraintCommand(EditPart child, Object constraint) {
TableModel table = (TableModel) child.getModel();
Rectangle rect = (Rectangle) constraint;
TableChangeConstraitCommand command = new TableChangeConstraitCommand(table, rect);
return command;
}
让DataBaseXYLayoutEditPolicy在createChangeConstraintCommand方法中返回一个TableChangeConstraitCommand即可。
五. 启动,查看效果
六. 给GraphicalViewer注册KeyHandle
KeyHandler keyHandler = new KeyHandler();
graphicalViewer.setKeyHandler(new GraphicalViewerKeyHandler(graphicalViewer).setParent(keyHandler));
keyHandler.put(KeyStroke.getPressed(SWT.F1, SWT.NONE), new RedoAction(this));
keyHandler.put(KeyStroke.getPressed(SWT.F2, SWT.NONE), new UndoAction(this));
KeyHandle :是对于按键的监听
KeyHandle可以使用setParent方法将多个KeyHandle组成按键的监听链,按键的监听从最下面一个KeyHandle一直往上遍历,只要其中一个KeyHandle对某一按键监听了,就执行对应的Action。
KeyHandler通过KeyStorke(按键、复合按键) 和 Action进行对应。
注意: 按键有按下(getPressed)和弹起(getReleased)的区别。
- Command在执行后,都会被放入CommandStack。
- UndoAction其实就是在CommandStack中,找到最后执行过的Command,调用其Undo方法。
- 同样的,RedoAction就是在CommandStatck中,找到最后一次Undo的Command,执行其redo方法。
七. 为ViewPart返回CommandStack
由于RedoAction 或UndoAction 需要依赖CommandStack ,通过ViewPart.getAdapter(CommandStack.class) 获得CommandStack对象,于是,我们需要给ViewPart返回CommandStack 对象,而它又存在于在EditDomain 中。
@Override
public Object getAdapter(Class adapter)
{
if ( CommandStack.class.equals(adapter) )
{
return this.graphicalViewer.getEditDomain().getCommandStack();
}
return super.getAdapter(adapter);
}
好了,完成了,在你调整完了Table的大小后,可以使用F1、F2进行撤销和重做。
八. 改用ActionRegistry
由于在其他地方还需要使用RedoAction 或UndoAction ,那么你可以考虑使用ActionRegister ,将Action对象初始化完毕后,再缓存在ActionRegister 里面。
//
actionRegistry.registerAction(new RedoAction(this));
IAction action = actionRegistry.getAction(ActionFactory.REDO.getId());
keyHandler.put(KeyStroke.getPressed(SWT.F1, SWT.NONE), action);
actionRegistry.registerAction(new UndoAction(this));
action = actionRegistry.getAction(ActionFactory.UNDO.getId());
keyHandler.put(KeyStroke.getPressed(SWT.F2, SWT.NONE), action);
}
private ActionRegistry actionRegistry = new ActionRegistry();
九. 其他
问题: 为什么按键选用F1和F2,而不是通常的Ctrl+Z和Ctrl+Y
是由于复合按键比单按键复杂,可以见我的另一篇博客。
十. 总结
- 认识了XYLayoutEditPolicy和简单的Command
- 认识了和Action想关的KeyHandle、KeyStroke、CommandStack、ActionRegistry