GEF源码分析(三) GEF 的树状构架 ___ Model/EditPart/Figure
树状对象模型 建立过程
如果要建立可编辑2D图形程序,比较基本的要有以下几个主要需求
- 一方面我们有一个model对象组,这些包含了拥有一些业务以及UI展现上的数据;
- 另一方面我们有一个视图它将包含一组可视化对象,这些可视化对象定义了如何在屏幕上描绘;
- 用户能够使用鼠标和键盘修改图形视图。这需要在程序的内部通过某种方式建立在UI对象和model关联方式,透过二者的关联,当视图发生改变时,需要引发model改变,而model也有可能由于某种业务逻辑发生改变,需要通知放映到视图上。
这样我们就提供给用户一个图形交互的方式来修改业务model,具有这种能力的程序我们可以称之为可编辑2D图形程序(a graphical editor)。
上一篇讨论到在GEF框架中形成了三个对应的树状对象模型。
为了达到之上的需求,GEF通过EditPart如上图建立了View和model之间的关联关系。
于是问题随之而来:
这些树状对象模型 如何?何时?创建
尤其困难的是通过怎样简捷的方法在EditPart中建立它们的关联呢?
GEF给出如下答案:
从上图可以看出在GEF是通过EditPartFactory根据以存在的Model 来创建并设置不同的EditPart。
EditPartFactory的接口如下:
EditPart createEditPart(EditPart context, Object model);
其中model是Object类型,因此可以看出在GEF对model没什么过多的约束,context是于要创建的EditPart有关联的EditPart,例如是将要创建EditPart的Parent。
这样GEF通过一下时序图就非常轻松的(学起来可不轻松:(),根据model对象框架建立了另外两个EditParts和Figures树状体系。[链接]见下附图 时序图。
其中在创建过程中重要的方法:
class ShapesEditor
protected void configureGraphicalViewer() { .. }
protected void initializeGraphicalViewer() {..}
class ShapesEditPartFactory
public EditPart createEditPart(EditPart context, Object modelElement) {
// get EditPart for model element
EditPart part = getPartForElement(modelElement);
// store model element in EditPart
part.setModel(modelElement);
return part;
}
/**
* Maps an object to an EditPart.
* @throws RuntimeException if no match was found (programming error)
*/
private EditPart getPartForElement(Object modelElement) {
//根据不同的model产生不同EditPart
if (modelElement instanceof ShapesDiagram) {
return new DiagramEditPart();
}
if (modelElement instanceof Shape) {
return new ShapeEditPart();
}
if (modelElement instanceof Connection) {
return new ConnectionEditPart();
}
throw new RuntimeException(
"Can't create part for model element: "
+ ((modelElement != null) ? modelElement.getClass().getName() : "null"));
}
class ShapeEditPart
public void setModel(Object model) {
if (getModel() == model)
return;
this.model = model;
}
protected IFigure createFigure() {
IFigure f = createFigureForModel();
f.setOpaque(true); // non-transparent figure
f.setBackgroundColor(ColorConstants.green);
return f;
}
/**
* Return a IFigure depending on the instance of the current model element.
* This allows this EditPart to be used for both sublasses of Shape.
*/
private IFigure createFigureForModel() {
//根据不同的model创建不同的figure
if (getModel() instanceof EllipticalShape) {
return new Ellipse();
} else if (getModel() instanceof RectangularShape) {
return new RectangleFigure();
} else {
// if Shapes gets extended the conditions above must be updated
throw new IllegalArgumentException();
}
}
至此、我们就得到了树状的MVC框架,但是,还是有些问题没有解决:
例如、已存在一个三角图形EditPart,我们想重用它,但是我们还需要增加(或删去)边框可调整的特性,如何保证无需重新建立一个新的EditPart,或者做出丑陋的继承,当功能不断组合后,出现无数子EditPart类?
在界面操作过程中,我们希望面对的是边框调整事件,或者是编辑文本事件,而不是原始的鼠标和键盘事件?
希望EditPart能够自动无误地把事件通知到相应的父及子EditPart中,同时能够按照正确的顺序对事件做出响应?
如何由框架自动完成Undo及Redo功能?
.....