注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

淡忘邻人

二十七,始发愤

 
 
 

日志

 
 
 
 

组织SWT/JFace控件的利器:Layout  

2011-04-18 21:00:41|  分类: JAVA |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
在可视化编程时代,大多数可视化的GUI开发工具都提供了按一定规则排列Form中的控件的功能。但是对于Java来说,支持可视化开发的工具并不多,虽 然有一些这样的工具,但它们大多是第三方的产品,稳定性方面有一些欠缺。因此,在很多时候使用Java编写GUI程序时,就要使用布局(Layout)来 控制Form上的控件的位置。

本文主要讨论如何使用SWT中提供的布局来安排控件的位置,并通过实例来演示这一过程。在SWT中提供了5 种布局:FillLayout, RowLayout, GridLayout, FormLayout, and StackLayout。下面我将详细讨论这5种布局的使用。

FillLayout

FillLayout是最简单的布局。它可以将控件横向或纵向进行排列,并且其中每个控件都有同样的宽度或高度。使用FillLayout一般分为2步。

1. 建立一个FillLayout对象。

2. 使用setLayout方法设置Shell对象的布局。

下面代码使用FillLayout在Shell上放了3个按钮,代码如下:

package layout;

import org.Eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;

public class TestFillLayout
{
 public static void main(String[] args)
 {
Display display = new Display();
Shell shell = new Shell(display, SWT.DIALOG_TRIM);
shell.setText("FillLayout演示");
shell.setSize(400, 300);

// 设置shell的布局
FillLayout layout = new FillLayout();
shell.setLayout(layout);

// 向shell添加控件
Button button1 = new Button(shell, SWT.PUSH);
button1.setText("按钮1");

Button button2 = new Button(shell, SWT.PUSH);
button2.setText("按钮2");

Button button3 = new Button(shell, SWT.PUSH);
button3.setText("按钮3");

shell.open();
while (!shell.isDisposed())
{
 if (!display.readAndDispatch())
 {
display.sleep();
 }
}
display.dispose();
 }
}

界面如图1所示。

组织SWT/JFace控件的利器:Layout - 在水一方 - 在水一方的博客
图 1 使用横向FillLayout的Shell界面

如果想要Shell上的控件纵向排列,可以在建立布局时将type属性设置成SWT.VERTICAL。代码如下:

FillLayout layout = new FillLayout();
layout.type = SWT.VERTICAL;
shell.setLayout(layout);

图2是控件纵向排列的效果图

组织SWT/JFace控件的利器:Layout - 在水一方 - 在水一方的博客
图 2 使用纵向FillLayout的Shell界面

FillLayout的构造函数重载了2次。其中一个构造函数有一个参数,这个参数就是type。因此,我们也可以通过FillLayout的构造函数对type赋值。

shell.setLayout(new FillLayout(SWT.VERTICAL));

RowLayout

RowLayout的功能和FillLayout差不多。只是它和FillLayout的最大区别是每 个控件并不一定是一样大小。而且RowLayout是按行排列,这一点和FillLayout是不同的。在一行排满后,就从下一行开始排列。和 RowLayout配合使用的还有一个RowData类。这个类可以设置每一个控件的大小。下面代码是一个使用RowLayout的小例子。

package layout;

import org.Eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;

public class TestRowLayout
{
 public static void main(String[] args)
 {
Display display = new Display();
Shell shell = new Shell(display, SWT.DIALOG_TRIM);
shell.setText("RowLayout演示");
shell.setSize(220, 200);

// 将Shell的布局设置成RowLayout
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
layout.spacing = 30;
layout.marginLeft = 30;
layout.marginTop = 30;
shell.setLayout(layout);

RowData rowData = new RowData();
rowData.height = 50;
rowData.width = 100;

// 向shell添加控件
Button button1 = new Button(shell, SWT.PUSH);
button1.setText("按钮1");
button1.setLayoutData(rowData);

Button button2 = new Button(shell, SWT.PUSH);
button2.setText("按钮2");

Button button3 = new Button(shell, SWT.PUSH);
button3.setText("按钮3");

shell.open();
while (!shell.isDisposed())
{
 if (!display.readAndDispatch())
 {
display.sleep();
 }
}
display.dispose();
 }
}

图3是使用RowLayout的效果图

组织SWT/JFace控件的利器:Layout - 在水一方 - 在水一方的博客
图3 RowLayout效果图

可 以在两个地方设置和RowLayout相关的数据,一个是RowData,它可以设置控件的大小。另外一个就是RowLayout本身,它可以设置控件开 始排列的起点坐标(marginLeft和marginTop)、以及控件之间的间距等信息(spacing)。在RowLayout中有个很重要的属性 justify。这个属性默认是false。当它为true时,将自动调整行或整列的控件,使其尽量占满一行或一列。

GridLayout

GridLayout是SWT中最重要的布局。这个布局十分强大,它可以满足大多数的需要。而且它 的网络可以通过Composite对象进行嵌套。GridLayout有两个构造函数。一个是默认的构造函数public GridLayout()。另外一个需要两个函数public GridLayout(int numColumns, boolean makeColumnsEqualWidth)。其中numColumns是这个网格的列数,而另外一个参数将使每一列等宽。下面的代码是一个完整的关于 GridLayout的例子。

package layout;

import org.Eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;

public class TestGridLayout
{
 public static void main(String[] args)
 {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("GridLayout演示");
GridLayout layout = new GridLayout();
layout.numColumns = 3;
layout.makeColumnsEqualWidth = true;
shell.setLayout(layout);

// 建立左上角的按钮
GridData data = new GridData(GridData.FILL_BOTH);
data.widthHint = 200; //按钮的初始宽度为200
Button one = new Button(shell, SWT.PUSH);

one.setText("按钮1");
one.setLayoutData(data);

// 建立一个Composite对象,并在上面放三个按钮
Composite composite = new Composite(shell, SWT.NONE);
data = new GridData(GridData.FILL_BOTH);
data.horizontalSpan = 2; // Composite的占两个Cell

composite.setLayoutData(data);
layout = new GridLayout();
layout.numColumns = 1;
layout.marginHeight = 15;
layout.marginRight = 150;
composite.setLayout(layout);
 
// 建立第二个按钮
data = new GridData(GridData.FILL_BOTH);
Button two = new Button(composite, SWT.PUSH);
two.setText("按钮2");
two.setLayoutData(data);

// 建立第三个按钮
data = new GridData(GridData.HORIZONTAL_ALIGN_END);
Button three = new Button(composite, SWT.PUSH);
three.setText("按钮3");
three.setLayoutData(data);

// 建立第四个按钮
data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
Button four = new Button(composite, SWT.PUSH);
four.setText("按钮4");
four.setLayoutData(data);

// 建立下面的一个长按钮
data = new GridData();
data.horizontalAlignment = GridData.FILL;
data.grabExcessHorizontalSpace = true;
data.horizontalSpan = 3;
data.verticalSpan = 2;
data.heightHint = 150;
Button five = new Button(shell, SWT.PUSH);
five.setText("按钮5");
five.setLayoutData(data);

shell.pack();
shell.open();
while (!shell.isDisposed())
{
 if (!display.readAndDispatch())
 {
display.sleep();
 }
}
display.dispose();
 }
}

上面的例子将网格设成3列,在第一行的第一列放置了第一个按钮。然后将一个Composite对象放到第一行第二、三列(data.horizontalSpan = 2),在这个对象上放到个按钮。最后在下面建立了第5个按钮。

FormLayout

FormLayout是SWT中最复杂的布局。在这一部分我将详细讨论FormLayout。这个布局虽然复杂,但它确可以对控件进行更多的控制。

FormLayout 和其它的布局类似,也有一个FormData类用于设置布局信息。但我其它的布局不同的是FormLayout使用另外一个类来控制控件的大小和位置,这 个类是FormAttachment。控件的上、下、左、右分别要4个FormAttachment对象来控制。通过这些FormAttachment对 象可以控制当前控件如何在它的父窗口中显示,以及和其它控件的相对位置。

在FormLayout中,描述位置的4个属性(left、 top、right、bottom)都是一个FormAttachment对象。而并不是一个简单的值。在FormAttachment中比较常用的属性 是numerator,这个属性描述控件的4个边距Shell的边缘的距离。

按百分比放置控件

可以通过FormAttachment的numerator属性设置百分比。下面的代码将一个按钮在它的父窗口的宽度的40%处放置按钮。当Shell的尽寸改变后,按钮的位置也随之变化,但按钮的大小并不改变。

Button button = new Button(shell, SWT.PUSH);
button.setText("按钮");
FormData data = new FormData();
data.left = new FormAttachment(40);
button.setLayoutData(data);

但 如果同时设置data的left和right属性又如何呢?如果是这样的话,那么这个按钮的尺寸就会改变。下面的例子将一个按钮放到水平方向中心的位置。 我们可以将left的比例设计为40%,而right的比例设置60%。如果这样设置,无论窗体如何变化,这个按钮始终在水平方向的中心。这是一个简单的 数学计算。如果一个按钮的左边在40%的位置,而右边在60%的位置,也就是说,按钮的右边距窗体的右边也是40%。这样可以算出,按钮的宽度占窗体的 20%(哈哈,要想使用FormLayout,可要有一定的数学基础啊!)。

Button button = new Button(shell, SWT.PUSH);
button.setText("按钮");
FormData data = new FormData();
data.left = new FormAttachment(40);
data.right = new FormAttachment(60);
button.setLayoutData(data);

不 过在使用FormAttachment同时给left和right或top和bottom赋值时,不能将这两个比例设成一样的,要不就将按钮压扁了(按钮 看不到了,宽或高为0)。如果想要按钮在中心位置,这两个比例的和必须是100。而且left(top)的比例要小于right(bottom)的比例。

设置控件的偏移量

SWT之所以提供了布局,目的就是让你尽量少使用绝对坐标来设置控件。但在有时,我们又必须使用绝对坐标。如果是这样的话,你可以使用控件的setLocation来设置,也可以使用FormAttachment提供的偏移量去达到同样的效果。

FormData data = new FormData();
data.left = new FormAttachment(0, 20);
data.top = new FormAttachment(0, 40);
button.setLayoutData(data);

上面的代码相当于setLocation(20, 40),即将按钮设置的位置设置成(20, 40)。

根据其它控件的调整位置

一般在窗体上都有不只一个控件,这些控件之间都是有一定关系的,它们的位置也是相对的。因此,FormLayout为我们提供了根据其它控件设置当控件位置的方法。如根据另外一个控件设置当前控件左边或右边的位置。

下面的例子将根据一个按钮的位置设置另外一个按钮的位置。有两个按钮,第二个按钮根据第一个按钮的底边设置自己的位置。

Button button1 = new Button(shell, SWT.PUSH);
button1.setText("按钮1");
FormData data1 = new FormData();
data1.top = new FormAttachment(20);
data1.left = new FormAttachment(40);
data1.right = new FormAttachment(50);
button1.setLayoutData(data1);
// 第二个按钮
Button button2 = new Button(shell, SWT.PUSH);
button2.setText("按钮2");
FormData data2 = new FormData();
data2.left = new FormAttachment(button1, 0, SWT.CENTER);
data2.top = new FormAttachment(button1);
button2.setLayoutData(data2);

上面的"按钮2"将根据"按钮1"将自己水平方向的位置设置成"按钮1"的中心位置。

StackLayout

我们在最后一部分来讨论StackLayout,并不是因为StackLayout在这5种布局中 最复杂,而是这个布局并不在org.Eclipse.swt.layout中,而在org.eclipse.swt.custom中。从这个布局的名子可 看出,它是将许多SWT控件放到一个集合中,这些控件有同样的尺寸和位置。但只有在最上面的控件才能被显示。

StackLayout只有 一个空的构造函数,它只有一个属性topControl,这个属必确定了哪一个控件可以被显示。这个属性默认值是null,也就是说,如果不设置它,那将 没有控件被显示在窗体上。但要注意的是,设置topControl并不会将StackLayout中控件删除。

package layout;

import org.eclipse.swt.events.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.SWT;

public class TestStackLayout
{
 public static void main(String[] args)
 {
Display display = new Display();
Shell shell = new Shell(display);
StackLayout layout = new StackLayout();
shell.setLayout(layout);
StackLayoutSelectionAdapter adapter = new StackLayoutSelectionAdapter(shell, layout);
Button one = new Button(shell, SWT.PUSH);
one.setText("按钮1");
one.addSelectionListener(adapter);
Button two = new Button(shell, SWT.PUSH);
two.setText("按钮2");
two.addSelectionListener(adapter);
Button three = new Button(shell, SWT.PUSH);
three.setText("按钮3");
three.addSelectionListener(adapter);
layout.topControl = one;
shell.open();
while (!shell.isDisposed())
{
 if (!display.readAndDispatch())
 {
display.sleep();
 }
}
display.dispose();
 }
}

class StackLayoutSelectionAdapter extends SelectionAdapter
{
 Shell shell;
 StackLayout layout;

 public StackLayoutSelectionAdapter(Shell shell, StackLayout layout)
 {
this.shell = shell;
this.layout = layout;
 }

 public void widgetSelected(SelectionEvent event)
 {
Control control = layout.topControl;
Control[] children = shell.getChildren();
int i = 0;
for (int n = children.length; i < n; i++)
{
 Control child = children[i];
 if (child == control)
 {
break;
 }
}
++i;
if (i >= children.length)
 i = 0;
layout.topControl = children[i];
shell.layout();
 }
}

上面这个例子在Shell上有三个按钮,通过按最上面显示的按钮,这三个按钮循环交替显示。
  评论这张
 
阅读(323)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017