LayoutManager布局管理
不要设置figure的大小,而是应该在父中用setConstraint方法设置子的大小,
就像在swt里我们使用layout来控制各个控件的摆放位置一样,在Draw2D里最好也把这个工作交给LayoutManager来做。除非是在自己实现的Layout里,一般程序里自己不要轻易使用setBounds()、setLocation()和setSize()这些方法控制图形的位置和大小,而应该在为每个图形设置了适当的LayoutManager后,通过setConstraint()和setPreferredSize()等方法告诉layoutmanager如何布局。
?
?
在之前没有理解LayoutManager,如是就以一种尊重原著的心态,在实现一个复杂的编辑器布局的时候,拼命的用draw2d默认提供的布局进行拼凑,最终结果是代码的复杂度和耦合度急剧上升。
其实如果换一种思路,就是一个容器里面除了要显示的子,不应该为了布局而额外出现一些IFigure,就算出现也应该是尽量少的出现。当默认的布局不够用的时候,应该尝试自己扩展一个有效的LayoutManager。
?
这里顺便提一下SWT的局限性:SWT里面容器组件的布局跟容器组件是绑定的,也就是说,如果一个组件里面需要多种布局。它就必须有多个子,然后每个子里面再选择布局。如果从设计上布局就是一个没有形状只有规则的子,这样就显得更合理。
?
LayoutManager接口:布局管理器的基础接口,其中layout方法最为重要,在此次处实现布局的规则。另外invalidate起到一个清空的作用。
?
AbstractLayout:抽象实现。里面增加了两个属性:preferredSize容器的首选大小,isObservingVisibility我的理解这个属性描述的是,是否完全可见。这个类提供了一个抽象方法供其子实现,calculatePreferredSize(IFigure container,int wHint, int hHint)计算容器的大小,另外在setConstraint里面对子元素的位置信息进行清空,位置变了需要重新计算。
setConstraint(IFigure figure, Object constraint):方法中第二个参数是根据布局的需要来传入的,不一定是Rectangle
?
对于一个真实有效的布局管理器来说,它必须做两件事情:
1.一个就是根据一定的规则,算出整个容器的大小。如果大小不可以改变,那么就不能改变。
2.在Layout方法里面定义出一套规则来摆放它的子节点。
?
XYLayout:自由布局,绝对定位的布局。XY中有一个Map constraints保存了子的尺寸。如下是XYLayout实现布局的代码:
?
?
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);}}??
第一步它获取父的x,y坐标offset,然后计算每个子的矩形区域Rectangle,其中对超出边界的矩形做了一些处理。里面
这句话没看明白:bounds = bounds.getCopy();没看懂。getConstraint中放的都是设置的Rectangle,而
getPreferredSize里面放的是首选矩形。
?
注意:这里的绝对定位是相对父容器来说的,而不是整个界面来说。
?
RulerLayout:继承自XYLayout,它是gef主要用来实现ZoomManager功能的时候自己扩展的,在gef中还有RulerFigure,RulerEditPart之类的,这个布局管理器并不通用。
?
public void layout(IFigure container) {List children = container.getChildren();Rectangle rulerSize = container.getClientArea();for (int i = 0; i < children.size(); i++) {IFigure child = (IFigure) children.get(i);Dimension childSize = child.getPreferredSize();int position = ((Integer) getConstraint(child)).intValue();if (((RulerFigure) container).isHorizontal()) {childSize.height = rulerSize.height - 1;Rectangle.SINGLETON.setLocation(position- (childSize.width / 2), rulerSize.y);} else {childSize.width = rulerSize.width - 1;Rectangle.SINGLETON.setLocation(rulerSize.x, position- (childSize.height / 2));}Rectangle.SINGLETON.setSize(childSize);child.setBounds(Rectangle.SINGLETON);}}?FreeformLayout:继承自XYLayout,它的布局方式跟XYLayout一样,只是重写了getOrigin(IFigure figure)方法,在获取Origin坐标的时候有所不同。
?
?
AbstractHintLayout:继承自AbstractLayout,它提供了一个calculateMinimumSize方法用于计算长度和宽度。AbstractHintLayout的子类都是尺寸敏感位置不敏感的相对布局。
?
?
还有好几种相对布局,暂时先不总结
BorderLayout:一个东南西北中的布局,里面有五个静态常量来描述位置。
?
?
?
?
?
?
?
?
?
?
?
?