-
布局管理器简介
VB,Delphi程序不需要布局管理器,而java GUI 程序卻需要,是因為java开发程序的目标是要跨平台的,而 每一个OS对屏幕的定义是不一样的。如果像 VB,Delphi那样使用绝对坐标定位界面组件,那么在windows下看着好好的界面,到了Linux,MacOS下,就变的一塌糊涂。除非你开发的java GUI只在Windows下运行,但即便如此,在不同的屏幕分辨率下,界面的形状也会大不一样!所以用了布局管理器的话,不论在说明OS,说明分辨率下,界面都不会变形。
SWT中主要的几种布局管理器如下所示:
FillLayout 充满式布局管理器,组件的大小会尽量充满整个容器。
RowLayout 行列式布局管理器,简单的排列组件。
GridLayout 网格式布局管理器,非常强大,可以胜任所有布局。
FormLayout 表格式布局管理器,通过创建组件各个边的距离来布局组件,和GridLayout一样强大。
StackLayout 堆栈式布局管理器,项书页一样只显示最前面的组件。
-
充满式(FillLayout 类)
FillLayout 是最简单的布局类,它把组件摆放在一排或一列,并强制组件大小一致。一般的组件的高度和最高组件相同,组件的宽度和最宽组件相同。另外,FillLayout 不能折行,不能设置边界距离和间距。
FillLayout 一般使用与任务栏,工具栏,Group中的一组复选框,或者容器中只有一个组件的时候。例如,如果一个shell内只有一个Group组件,那么将FillLayout用于Shell,则其内的Group将完全充满Shell.
FillLayout 默认情况下,是从左到右以此排列的,如果项上下来的话,只需要,将“new FillLayout()”改为“new FillLayout(SWT.VERTICAL)”,则可以上下来显示了。
-
行列式(RowLayout类)
RowLayout可以使组件折行显示,并可以设置边界距离和间距。另外,它可以对每个组件通过setLayoutData方法设置RowData对象,RowData用来设置组件的大小。
其中相应的代码 new RowLayout(); 的时候还可以对RowLayout进行设置(代码设置和页面desigin设置都可以),如:组件和容器上边缘距离,左边缘...组件之间间隔(spacing)等等。
使用rowLayout.wrap控制自动折行(默认为true),可以通过RowLayout的详细属性的设定来改变,也可以通过代码来实现,rowLayout.wrap = false;效果相同,页面上的组件会不折行的显示(后面的就看不到了,晕!)
使用SWT.VERTICAL式样, 则变为垂直排列组件。同样可以通过RowLayout的详细属性的设定来改变。
使用RowLayout.pack控制组件大小(默认为true,大小可以控制)RowLayout.pack=false,组件大小相同。
使用RowLayout.justify控制空间伸展(默认为false)rowLayout.justify=true,让组件可以根据空间进行伸展。
使用RowData更改按钮的外观
当RowLayout.pack=false 的时候,进行其他它的设置的时候,只是改变按钮在容器中的布局,而对按钮的外观形状(如:大小)没有影响。
如果要改变按钮本身的外观,则要使用RowData类,RowData称为布局管理类,为RowLayout专用。GridLayout类也有专门的布局管理类GridData,GridData的目的也和RowData一样,即改变容器中组件的外观形状。
RowData最常用的格式是:new RowData(int width ,int height)。
例如:b1.setLayoutData(new RowData(30,50)); 是把b1組件设定大小!
- 网格式(GridLayout 类)
GridLayout类可能是最常用,功能最强大的标准布局类了,当然它也最复杂。GridLayout的布局方式是把容器里的组件摆放在一个个格子里,它有许多可设置项,并且和RowLayout一样也有专用的布局管理类GridData。GridData的使用颇为复杂,而GridLayout的强大之处也在于它可以通过GridData来设置每一个组件的外观形状!
使用GridLayout.numColumns设置列数,numColumns 是GridLayout 最重要的属性,通常它是要第一个设置的属性。GridLayout.numColumns=2,就把容器分成2列。
使用makeColumnsEqualWidth把组件等距离分开(默认为false),这时相当于把容器等距离分成几份(横向)。
GridLayout边距和间距的设置和RowLayout类似:
同样可以分别设置horizontalSpacing(列之间的间距) 和verticalSpacing (垂直间距) ,RowLayout 中的间距格局组件是水平 or 垂直排列来设置水平间距或垂直间距。
不同的是,左边距右边距统一成 marginWidth ,上边距下边距,统一成 marginHeigth.
使用GridData 来控制复杂布局,GridLayout 和 GridData 相结合可以变化出很多复杂的布局方式。 需要注意的是:一个GridData 对象只能用于一个组件,如果多个组件共用,会引起界面的紊乱。
1. horizontalSpan 是设置组件占用的列数。给出一个实例,代码如下:
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setLayout(new GridLayout(2,false)); //2列
shell.setMinimumSize(new Point(5, 26));
shell.setSize(500, 365);
shell.setText("SWT Application");
shell.open();
new Button(shell, SWT.NONE).setText("b1");
new Button(shell, SWT.NONE).setText("button2");
final Button button = new Button(shell, SWT.NONE);
GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
gridData.widthHint = 24;
button.setLayoutData(gridData);
button.setText("b3");
new Button(shell, SWT.NONE).setText("button4");
new Button(shell, SWT.NONE).setText("button5");
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
2.上面例子中b3按钮拥有2列布局空间,但是大小没有变,组件的占用空间和拥有的空间可以不同,如果要b3也占用2列空间,只需要将上面代码中的定义GridData的那句改为:GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);即可。GridData.HORIZONTAL_ALIGN_FILL是一个int常量,叫“水平对齐式充满”。
3.gridData.FILL_HORIZONTAL(水平抢占式充满),它会将水平方向所有的空间占为己有。
4.gridData.FILL_BOTH(双向抢占式),相当于水平和垂直抢占式合并 的效果。
5.gridData.horizontalAlignment和gridData.verticalAlignment,这两个属性用来设置组件在格子里的对齐方式。它有4种对齐方式:BEGINNING(默认值)左对齐,CENTER,居中,END,右对齐,FILL,添满。
6.gridData.horizontalIndent 属性可以使组件向右移动指定长度(像素),此属性只有当horizontalAlignment设为BEGINNING(默认值)时有效。
7.gridData.grabExcessHorizontalSpace、gridData.grabExcessVerticalSpace(默认值false)
这两个属性主要是用在Text,List中,效果是:当组件所在的容器大小改变时,组件的占有空间也自动的增大或减小。例如:设置一个Text 组件为grabExcessHorizontalSpace= true,那么当用户调整窗口,导致容器宽度发生变化时,Text所在的列空间也会随着变化(组件的大小不会变化),但在同一行的其他组件会保持宽度不变。
8.gridData.widthHint、gridData.heightHint 属性可以改变组件的宽度和高度,但前提是不与GridLayout的其他设置相矛盾。
- 堆栈式(StackLayout类)
StackLayout 称作堆栈式布局,所谓堆栈式,就是像一副叠在一起的扑克牌,只显示最上面的那个扑克(面板),和awt/swing里面的cardLayout的感觉是一样的,下面是一个简单的例子:
private static Text text2;
private static Text text1;
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setLayout(new FillLayout());
shell.setMinimumSize(new Point(5, 26));
shell.setSize(500, 365);
shell.setText("SWT Application");
shell.open();
final Composite composite = new Composite(shell, SWT.NONE);
final StackLayout stackLayout = new StackLayout();
composite.setLayout(stackLayout);
text1 = new Text(composite, SWT.BORDER);
text1.setText("text1");
text2 = new Text(composite, SWT.BORDER);
text2.setText("text2");
final Composite composite_1 = new Composite(shell, SWT.NONE);
final GridLayout gridLayout = new GridLayout();
gridLayout.marginWidth = 80;
gridLayout.marginTop = 30;
gridLayout.numColumns = 2;
composite_1.setLayout(gridLayout);
final Button show1Button = new Button(composite_1, SWT.NONE);
show1Button.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
//关键代码就下面2行, 下面首先是让text1放在上面(top)出来
stackLayout.topControl = text1;
composite.layout(); //刷新,否则,看不到效果的
}
});
final GridData gd_show1Button = new GridData();
show1Button.setLayoutData(gd_show1Button);
show1Button.setText("show1");
final Button show2Button = new Button(composite_1, SWT.NONE);
show2Button.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
stackLayout.topControl = text2;
composite.layout();
}
});
final GridData gd_show2Button = new GridData();
show2Button.setLayoutData(gd_show2Button);
show2Button.setText("show2");
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
- 表格式(FormLayout 类)
FormLayout 是一种和GridLayout一样强大,而且还很灵活、精确的布局,这个布局是SWT2.0版新增的,通常GridLayout和FormLayout 是可以做到相同的效果的,但有时使用FormLayout 会更有效,不会像GridLayout因容器大小变化而导致布局错位。
使用marginWidth、marginHeight设置边距(左边距,上边距)。
使用FormData的构造函数
FormLayout 也有自己的布局管理类FormData,它的使用方法是:new FormData() 或 new FormData(int width, int height)
FormAttachment 是在FormData下的,更进一步地布局管理类,它的用法主要体现在它的不同构造函数上。
1. new FormAttachment(int numerator, int offset)
如下例,button1的顶边(formData.top)离shell容器的空白边距是shell容器总体空白长度的60%,偏移点数(points)为0,代码如下:
shell.setLayout( new FormLayout());
new Text(shell,SWT.BORDER).setText( " text1 " );
Button button1 = new Button(shell,SWT.NONE);
button1.setText( " button1 " );
FormData formData = new FormData();
formData.top = new FormAttachment( 60 , 0 ); // button1的顶部应用FormAttachment设置
button1.setLayoutData(formData);
...
如果将new FormAttachment(60,0);改为new FormAttachment(60,10); 则button1先60%,再下降10个像素。
new FormAttachment(int numerator)相当于new FormAttachment(int numerator, int offset)当offset=0时。
new FormAttachment(int numerator, int offset)相当于new FormAttachment(int numerator,int denominator, int offset) 当denominator=100 时,其中denominator 是分母,例如FormAttachment(30,50,0); 和FormAttachment(60,10);效果是一样的。
2. new FormAttachment(Control control,int offset, int alignment)
参数1是一个Control类,一般在使用的时候传入一个组件(如文本框)来做参数。应用此FormAttachment的组件将依据参数1的control为基准来布局,offset为离control的偏移量(单位:像素),alignment为对齐方式,下面是例子:
Text text1 = new Text(shell,SWT.BORDER);
text1.setLayoutData( new FormData( 100 , 50 ));
FormData formData = new FormData();
// 以text1为基准偏移50个像素
FormAttachment formAttachment = new FormAttachment(text1, 50 );
formData.top = formAttachment;
formData.left = formAttachment;
// 将button1应用FormData
Button button1 = new Button(shell,SWT.None);
button1.setText( " button1 " );
button1.setLayoutData(formData);
上例最终显示结果就是,button1以 text1为基准, 分别向右和向下 偏移50个像素。
可以把“FormAttachment formAttachment = new FormAttachment(text1,50);”这句,替换一下,就可以得到其他的结果。当前这句new FormAttachment(text1,50);不带alignment 相当于FormAttachment(text1,50,SWT.DEFAULT); 。当alignment =SWT.CENTER的时候,button1和text1的中心重合,因此在显示结果上看不到button1了。alignment =SWT.LEFT,以text1 的左边界为基准偏移,alignment =SWT.RIGHT,为右基准。alignment =SWT.TOP,alignment =SWT.BOTTOM,以上下边界为基准。