draw2d详述(IFigure)

1.IFigure

IFigure接口是所有Figure的基础接口,里面有很多方法,这里只列出部分自己觉得有用的方法:

(1)add(IFigure figure, Object constraint, int index):添加一个子,并且指定其约束和位置:

public void add(IFigure figure, Object constraint, int index) {
		if (children == Collections.EMPTY_LIST)
			children = new ArrayList(2);
		if (index < -1 || index > children.size())
			throw new IndexOutOfBoundsException("Index does not exist"); //$NON-NLS-1$

		// Check for Cycle in hierarchy
		for (IFigure f = this; f != null; f = f.getParent())
			if (figure == f)
				throw new IllegalArgumentException(
						"Figure being added introduces cycle"); //$NON-NLS-1$

		// Detach the child from previous parent
		if (figure.getParent() != null)
			figure.getParent().remove(figure);

		if (index == -1)
			children.add(figure);
		else
			children.add(index, figure);
		figure.setParent(this);

		if (layoutManager != null)
			layoutManager.setConstraint(figure, constraint);

		revalidate();

		if (getFlag(FLAG_REALIZED))
			figure.addNotify();
		figure.repaint();
	}

(2)getPreferredSize:获取首选大小,这个大小多半会在layout里面用到。

(3)isCoordinateSystem:是否使用相对坐标

(4)isFocusTraversable:是否可以得到焦点

(5)isMirrored:是否有镜像效果

(6)isOpaque:是否透明

(7)paint(Graphics graphics):组件最重要的方法,画。

public void paint(Graphics graphics) {
		if (getLocalBackgroundColor() != null)
			graphics.setBackgroundColor(getLocalBackgroundColor());
		if (getLocalForegroundColor() != null)
			graphics.setForegroundColor(getLocalForegroundColor());
		if (font != null)
			graphics.setFont(font);

		graphics.pushState();
		try {
			paintFigure(graphics);
			graphics.restoreState();
			paintClientArea(graphics);
			paintBorder(graphics);
		} finally {
			graphics.popState();
		}
	}

 可以看出它把画这个行为分解了:

protected void paintFigure(Graphics graphics) {
		if (isOpaque())
			graphics.fillRectangle(getBounds());
		if (getBorder() instanceof AbstractBackground)
			((AbstractBackground) getBorder()).paintBackground(this, graphics,
					NO_INSETS);
	}

看它的透明是怎样实现的:把父画一遍就OK,多简单。

protected void paintClientArea(Graphics graphics) {
		if (children.isEmpty())
			return;

		boolean optimizeClip = getBorder() == null || getBorder().isOpaque();

		if (useLocalCoordinates()) {
			graphics.translate(getBounds().x + getInsets().left, getBounds().y
					+ getInsets().top);
			if (!optimizeClip)
				graphics.clipRect(getClientArea(PRIVATE_RECT));
			graphics.pushState();
			paintChildren(graphics);
			graphics.popState();
			graphics.restoreState();
		} else {
			if (optimizeClip)
				paintChildren(graphics);
			else {
				graphics.clipRect(getClientArea(PRIVATE_RECT));
				graphics.pushState();
				paintChildren(graphics);
				graphics.popState();
				graphics.restoreState();
			}
		}
	}
protected void paintChildren(Graphics graphics) {
		for (int i = 0; i < children.size(); i++) {
			IFigure child = (IFigure) children.get(i);
			if (child.isVisible()) {
				// determine clipping areas for child
				Rectangle[] clipping = null;
				if (clippingStrategy != null) {
					clipping = clippingStrategy.getClip(child);
				} else {
					// default clipping behaviour is to clip at bounds
					clipping = new Rectangle[] { child.getBounds() };
				}
				// child may now paint inside the clipping areas
				for (int j = 0; j < clipping.length; j++) {
					if (clipping[j].intersects(graphics
							.getClip(Rectangle.SINGLETON))) {
						graphics.clipRect(clipping[j]);
						child.paint(graphics);
						graphics.restoreState();
					}
				}
			}
		}
	}
 
protected void paintBorder(Graphics graphics) {
		if (getBorder() != null)
			getBorder().paint(this, graphics, NO_INSETS);
	}
 

其实画的过程还是挺清晰的,就是从底往上一层层的画。只是,画并不难,难的是算,如何让子进行排列这是个棘手的事。

2.LayoutManager在Figure里面的应用

在Figure里面,所有涉及到获取大小位置信息的,都要从LayoutManager里面过一遍,经过它计算后才能够被使用者获取到,有时候吧,我们总会很2的感觉自己获取的值怎么是什么样的,其实就是对里面的细节没有像清楚。

public Dimension getMinimumSize(int wHint, int hHint) {
		if (minSize != null)
			return minSize;
		if (getLayoutManager() != null) {
			Dimension d = getLayoutManager().getMinimumSize(this, wHint, hHint);
			if (d != null)
				return d;
		}
		return getPreferredSize(wHint, hHint);
	}
public Dimension getPreferredSize(int wHint, int hHint) {
		if (prefSize != null)
			return prefSize;
		if (getLayoutManager() != null) {
			Dimension d = getLayoutManager().getPreferredSize(this, wHint,
					hHint);
			if (d != null)
				return d;
		}
		return getSize();
	}
 
public void setConstraint(IFigure child, Object constraint) {
		if (child.getParent() != this)
			throw new IllegalArgumentException("Figure must be a child"); //$NON-NLS-1$

		if (layoutManager != null)
			layoutManager.setConstraint(child, constraint);
		revalidate();
	}
 
final class LayoutNotifier implements LayoutManager {

		LayoutManager realLayout;
		List listeners = new ArrayList(1);

		LayoutNotifier(LayoutManager layout, LayoutListener listener) {
			realLayout = layout;
			listeners.add(listener);
		}

		public Object getConstraint(IFigure child) {
			if (realLayout != null)
				return realLayout.getConstraint(child);
			return null;
		}

		public Dimension getMinimumSize(IFigure container, int wHint, int hHint) {
			if (realLayout != null)
				return realLayout.getMinimumSize(container, wHint, hHint);
			return null;
		}

		public Dimension getPreferredSize(IFigure container, int wHint,
				int hHint) {
			if (realLayout != null)
				return realLayout.getPreferredSize(container, wHint, hHint);
			return null;
		}

		public void invalidate() {
			for (int i = 0; i < listeners.size(); i++)
				((LayoutListener) listeners.get(i)).invalidate(Figure.this);

			if (realLayout != null)
				realLayout.invalidate();
		}

		public void layout(IFigure container) {
			boolean consumed = false;
			for (int i = 0; i < listeners.size(); i++)
				consumed |= ((LayoutListener) listeners.get(i))
						.layout(container);

			if (realLayout != null && !consumed)
				realLayout.layout(container);
			for (int i = 0; i < listeners.size(); i++)
				((LayoutListener) listeners.get(i)).postLayout(container);
		}

		public void remove(IFigure child) {
			for (int i = 0; i < listeners.size(); i++)
				((LayoutListener) listeners.get(i)).remove(child);
			if (realLayout != null)
				realLayout.remove(child);
		}

		public void setConstraint(IFigure child, Object constraint) {
			for (int i = 0; i < listeners.size(); i++)
				((LayoutListener) listeners.get(i)).setConstraint(child,
						constraint);
			if (realLayout != null)
				realLayout.setConstraint(child, constraint);
		}
	}

 这里还有个事件监听,实时对container重新计算。上述是LayoutManager在IFigure里面的使用。

3.LayoutManager:

LayoutManager的几个接口都是在Figure类里面用到,其中比较关键的void layout(IFigure container);是在它的LayoutNotifier里面调用的,当监听到需要改变布局的时候,就会调用此方法。

(1)XYLayout:

protected Dimension calculatePreferredSize(IFigure f, int wHint, int hHint) {
		Rectangle rect = new Rectangle();
		ListIterator children = f.getChildren().listIterator();
		while (children.hasNext()) {
			IFigure child = (IFigure) children.next();
			Rectangle r = (Rectangle) constraints.get(child);
			if (r == null)
				continue;

			if (r.width == -1 || r.height == -1) {
				Dimension preferredSize = child.getPreferredSize(r.width,
						r.height);
				r = r.getCopy();
				if (r.width == -1)
					r.width = preferredSize.width;
				if (r.height == -1)
					r.height = preferredSize.height;
			}
			rect.union(r);
		}
		Dimension d = rect.getSize();
		Insets insets = f.getInsets();
		return new Dimension(d.width + insets.getWidth(), d.height
				+ insets.getHeight()).union(getBorderPreferredSize(f));
	}

 计算首选大小

public void layout(IFigure parent) {
		Iterator children = parent.getChildren().iterator();
		Point offset = getOrigin(parent);
		IFigure f;
		while (children.hasNext()) {
			f = (IFigure) children.next();
			Rectangle bounds = (Rectangle) getConstraint(f);
			if (bounds == null)
				continue;

			if (bounds.width == -1 || bounds.height == -1) {
				Dimension preferredSize = f.getPreferredSize(bounds.width,
						bounds.height);
				bounds = bounds.getCopy();
				if (bounds.width == -1)
					bounds.width = preferredSize.width;
				if (bounds.height == -1)
					bounds.height = preferredSize.height;
			}
			bounds = bounds.getTranslated(offset);
			f.setBounds(bounds);
		}
	}
 

计算布局:最终会把计算到的值,赋值给IFigure:f.setBounds(bounds);

(2)其他的以后再分析,其实就是按照某种规则算,算大小什么的,其它的都是浮云。

猜你喜欢

转载自lengbingteng-163-com.iteye.com/blog/1528773
今日推荐