作为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; }
没看的很懂,大致意思就那样,重绘脏区域。