以下内容是学习"The Definitive Guide to SWT and JFace"(SWT/JFace权威指南)做的笔记
对于Window编程来说, 我们一般不会涉及到布局这个概念,因为基本上我们都是直接设置控件的大小, 位置等布局信息, 但是对于java来说就不一样了, 它涉及到跨平台的问题, 控件的位置和大小不是由它本身来控制的,因此我们不会看到控件有x, y, width, height等属性,而必须通过外面LayoutData和Layout来控制控件的位置和大小,这个是使用Java进行客户端编程必须转变的一个观念,当然这个也不是绝对,后面我们也会看到不使用布局的做法,但是我们一般不提倡这样做
Layout可以理解为它是控件和其所在容器之间的一层抽象, 它决定了控件在容器中的位置, 而且它是与平台无关的, 它会根据容器大小的变动来调整控件的尺寸.而且容器只能设置一种布局方式, 其包含的控件的布局是不依赖其他容器的
首先要介绍的是FillLayout, 它是所有布局中最简单的一种, 使用了该布局的容器中的所有控件将以同一尺寸放在一行或者一列中, 它有一个type属性,用来指定布局是采用列排列还行排列, type的属性值为SWT.HORIZONTAL和SWT_VERTICAL, 默认情况下是行排列, 因为这个type是一个int常量,如果这个常量既不是水平也不是垂直的话,他们系统将默认是垂直排列
接下来是RowLayout,跟FillLayout比较类似,都是按行或列排列包含在容器中的控件, 唯一不同的就是不会限制所有的控件采用同一大小, 而且如果一行或一列排列不下时会自动换行或者换列, 在使用RowLayout的时候,还会用到RowData类, 容器中的控件将通过它来制定自己的大小, RowLayout将根据每个控件的RowData信息来决定控件在整个容器中放置的位置, RowData可以直接在构造函数中通过width和height参数设置,也可以将width和height包装成Point对象作为其构造参数来设置其大小, RowLayout除了有一个跟FillLayout一样的type属性之外,还有另外几个属性需要介绍一下:
justify属性为true表示位于同一列或者同一行中的控件之间的间距相等;
marginBottom(Left, Right, Top)设置边距;
space指定间距;
wrap指定是否换行;
所有的布局都可以通过GridLayout来实现, 它也是我们用的最多的布局, 它采用表格的形式来放置容器所包含的控件, numColumns是该布局最重要的属性, 他决定了布局的结构, 所有的控件将从左到右被放在容器中, 它还有一些其他的属性:
horizontal(vertical)Spacing指定相邻单元格间距;
makeColumnsEqualWidth 是否强制同宽;
marginHeight(Width, Top, Bottom)设置指定边距;
我们还可以结合给控件指定GridData来进行布局, 但是GridData不能在控件之间公用, 它的一些属性必须说明:
grabExcessHorizontal(Vertical)Space为true的意思是指定控件所在单元格将获取所在行(列)剩余的所有空间, 如果一行(列)有多个控件设定该属性为true则只有第一个设置有效, 注意这里只的是cell并不是控件;
height(width)Hint设置控件的最小高(宽),注意这里指的是控件而不是单元格;
horizontal(vertical)Alignment:这个属性用来设置控件在单元格中的对其方式,有BEGINNING(左对齐),CENTER(居中),END(右对齐),FILL(填满整个单元格)几个值;
horizontal(vertical)Indent:这个是用来水平(垂直)方向上设置控件到单元格之间的间隔;
horizontal(vertical)Span:是用来指定控件在水平(垂直)方向上所占用的单元格;
GridData还有一些常量需要解释一下,BEGINNING,CENTER,END,FILL是用来设置对其方式的,不能作为构造函数的style参数, FILL_BOTH相当于将horizontalAlignment, verticalAlignment设置为FILL加上grabExcessHorizontalSpace和grabExcessVerticalSpace设置为true, 也就是说在构造函数的style参数设置为该值相当于设置了4个属性;FILL_HORIZONTAL = (horizontalAlignment = FILL) + (grabExcessHorizontalSpace=true); FILL_VERTICAL = (verticalAlignment = FILL) + (grabExcessVerticalSpace=true); GRAB_HORIZONTAL = (grabExcessHorizontalSpace =true); GRAB_VERTICAL = (grabExcessVerticalSpace =true), 类似HORIZONTAL_ALIGN_BEGINNING这样的从字面都可以知道意思了
FormLayout是所有布局里面最复杂的一种, 它也使用到自己的LayoutData:FormData, 另外它还会在FormData中通过使用FromAttachment来控制关联控件的位置, FormData可以设置四个FormAttachment实例,分别表示控件的四边与相对控件之间的位置关系, FormAttachment有以下几个成员变量:
alignment 用来指定关联的控件的某个边和相对控件之间的对齐方式, 如果关联的是上下位置,那么可以设置SWT.TOP, SWT.CENTER, SWT.BOTTOM,是左右位置可以设置SWT.LEFT, SWT.CENTER, and SWT.RIGHT, 该属性一般在指定的相对控件不是容器的时候使用, 否则会没有效果;
control属性指的是相对哪个控件,默认情况下是指的关联控件所在的容器;
denominator 是分母默认是100,这个一般不设置;
numerator是分子, 这两个值在control是关联对象的容器的时候才有意义, 用来指定应用的控件到容器关联边在整个容器中的百分比,说白了就是相对位置;
offset是偏移量,说白了就是关联控件与相对控件指定边之间的绝对位置
从FormAttachment的构造函数我们就可以看出来,一般哪些属性是一起设置的, 比如只设置control, 同时设置control和offset, 同时设置control, offset和alignment, 只设置分母, 同时设置分母和分子, 同时设置分母分子和偏移量
StackLayout是一个用的很少的布局, 从字面意思我们可以看出来, 它是将使用该布局的容器内的所有控件位置,大小设置为相同, 然后层叠在一起,只有位于最上面控件可见, 它使用topControl来指定哪个控件位于堆栈最上层并可见, 如果设置为null表示所有控件均不可见, 设置之后并调用容器的layout()方法才能使指定的控件可见
如何自定义布局
通过学习如何自定义布局,可以对SWT的布局实现做深层次的理解
自定义布局需要继承Layout类,并实现compluteSize和layout方法, 关联控件会调用compluteSize方法根据当前控件所包含子控件的大小计算出一个最小的尺寸值,返回值是Point里面的就是高宽值,就是确定要布局的容器的作用范围,而调用layout方法则是为容器中的每一个控件通过调用其setBounds方法来设置位置和大小, 如果需要更多的信息来帮助对控件进行布局,那么可以自己顶一个类来封装这些信息然后通过setLayoutData设置给control.
不使用布局
如果你不要面对垮平台,以及根据布局自动调整容器中的控件,那么也可以不通过布局来确定控件的位置和大小,通过自定义我们知道,布局都是通过调用里面控件的setBounds方法来确定控件的位置的,所以我们要做的就是直接调用控件的setBunds方法而已.