作为gef的展现层draw2d以其轻量灵活著称,在了解gef的同事,如果不花足够多的时间了解draw2d,就相当你有一半是无知的。
1.LightweightSystem与GraphicalViewerImpl:
它为SWT与draw2d建立联系,使得Figure能够很好的被Canvas管理。
要达到这个目的,必须做三件事:1.创建一个Canvas。2.创建一个LightweightSystem,并且把Canvas对象传递给它。3.创建一个rootFigure并且把它传递给LightweightSystem。这样LightweightSystem就能管理Canvas和rootFigure的关系了。
这三件事在GraphicalViewerImpl里面是可以找的到的:
protected LightweightSystem createLightweightSystem() {
return new LightweightSystem();
}
创建LightweightSystem
public Control createControl(Composite composite) {
setControl(new Canvas(composite, SWT.NO_BACKGROUND));
return getControl();
}
protected void hookControl() {
super.hookControl();
getLightweightSystem().setControl((Canvas) getControl());
getControl().addFocusListener(lFocus = new FocusListener() {
public void focusGained(FocusEvent e) {
handleFocusGained(e);
}
public void focusLost(FocusEvent e) {
handleFocusLost(e);
}
});
}
创建Canvas并把它赋给LightweightSystem
protected void setRootFigure(IFigure figure) {
rootFigure = figure;
getLightweightSystem().setContents(rootFigure);
}
rootFigure也被赋给LightweightSystem了。
public void setEditDomain(EditDomain domain) {
super.setEditDomain(domain);
// Set the new event dispatcher, even if the new domain is null. This
// will dispose
// the old event dispatcher.
getLightweightSystem().setEventDispatcher(
eventDispatcher = new DomainEventDispatcher(domain, this));
}
另外还传递了一个DomainEventDispatcher给LightweightSystem了。
DomainEventDispatcher是一个事件调度器,它继承自SWTEventDispatcher,在DomainEventDispatcher里面,它是把获取到的事件,转发给EditDomain进行处理,这个可以跟前面EditDomain能够获取到事件这一事实穿起来。
总结:在GraphicalViewerImpl里面创建一个LightweightSystem,并且让它管理SWT和draw2d相关组件。当GraphicalViewerImpl要刷新是,也是直接调用LightweightSystem的UpdateManager进行刷新。
2.LightweightSystem的内部:
(1)我们知道Figure不是SWT控件,但是却能够监听很多事件,是谁告诉它的呢?是它的SWT父canvas,canvas会监听事件,然后把事件给EventDispatcher,gef里面是DomainEventDispatcher,DomainEventDispatcher会把事件给EditDomain,EditDomain会把事件给当前活动的tool,tool会给editpart进行处理。(整条路通了)
protected void addListeners() {
EventHandler handler = createEventHandler();
canvas.getAccessible().addAccessibleListener(handler);
canvas.getAccessible().addAccessibleControlListener(handler);
canvas.addMouseListener(handler);
canvas.addMouseMoveListener(handler);
canvas.addMouseTrackListener(handler);
canvas.addKeyListener(handler);
canvas.addTraverseListener(handler);
canvas.addFocusListener(handler);
canvas.addDisposeListener(handler);
canvas.addListener(SWT.MouseWheel, handler);
canvas.addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
LightweightSystem.this.controlResized();
}
});
canvas.addListener(SWT.Paint, new Listener() {
public void handleEvent(Event e) {
LightweightSystem.this.paint(e.gc);
}
});
}
(2)上面说道的只是一条路,事件的响应和处理。在LightweightSystem里面,所以设计到对Figure的重绘都是在UpdateManager里面进行的。
UpdateManager抽象类里面,主要是描绘脏区域,以及对脏区域进行重绘。
public void addDirtyRegion(IFigure figure, Rectangle rect) {
addDirtyRegion(figure, rect.x, rect.y, rect.width, rect.height);
}
public synchronized void performUpdate(Rectangle exposed) {
addDirtyRegion(root, exposed);
performUpdate();
}
把rootFigure脏的位置,标记为脏。
public synchronized void performUpdate() {
if (isDisposed() || updating)
return;
updating = true;
try {
performValidation();
updateQueued = false;
repairDamage();
if (afterUpdate != null) {
RunnableChain chain = afterUpdate;
afterUpdate = null;
chain.run(); // chain may queue additional Runnable.
if (afterUpdate != null)
queueWork();
}
} finally {
updating = false;
}
}
刷新界面,repairDamage方法即是重绘的方法,
protected void repairDamage() {
Iterator keys = dirtyRegions.keySet().iterator();
Rectangle contribution;
IFigure figure;
IFigure walker;
while (keys.hasNext()) {
figure = (IFigure) keys.next();
walker = figure.getParent();
contribution = (Rectangle) dirtyRegions.get(figure);
// A figure can't paint beyond its own bounds
contribution.intersect(figure.getBounds());
while (!contribution.isEmpty() && walker != null) {
walker.translateToParent(contribution);
contribution.intersect(walker.getBounds());
walker = walker.getParent();
}
if (damage == null)
damage = new Rectangle(contribution);
else
damage.union(contribution);
}
if (!dirtyRegions.isEmpty()) {
Map oldRegions = dirtyRegions;
dirtyRegions = new HashMap();
firePainting(damage, oldRegions);
}
if (damage != null && !damage.isEmpty()) {
// ystem.out.println(damage);
Graphics graphics = getGraphics(damage);
if (graphics != null) {
root.paint(graphics);
releaseGraphics(graphics);
}
}
damage = null;
}
没看的很懂,大致意思就那样,重绘脏区域。