java swt 布局管理器_JAVA.SWT/JFace: SWT布局管理器

本文详细介绍了Java SWT中的布局管理器,包括FillLayout、RowLayout、GridLayout、FormLayout和StackLayout。通过实例展示了各种布局如何设置和使用,以及如何自定义布局管理器实现特定的布局需求。通过对控件大小、位置的调整,帮助开发者更好地组织用户界面。

7.1 布局管理器概述

FillLayout(充满式布局):在单行或单列中放置相同大小的控件,是最简单的布局。

RowLayout(行列式布局):在单行或者多行中放置控件,应用了fill、wrap和spacing等选项。

GridLayout(网格式布局):向表格一样放置控件。

FormLayout(表格式布局):与GridLayout功能差不多的布局,可以通过定义4个边的“附加值”来放置控件。

StackLayout(堆栈式布局):类似堆栈式的布局,只显示最上方的控件。

7.2 FillLayout(充满式布局)

规则:试图填充一行或一列,尽可能的充满整个面板,并且强制所有控件平均分配大小。FillLayout不会自动执行,也不能设置每个控件之间的空隙,但能够指定面板的四周的空白。

FillLayout layout = new FillLayout(SWT.VERTICAL);

FillLayout layout = new FillLayout();

layout.type = SWT.VERTICAL; // 默认为:SWT.HORIZONTAL

水平填充(SWT.HORIZONTAL):

21377574_1.jpg

垂直填充(SWT.VERTICAL):

21377574_2.jpg

设置四周补白:

FillLayout layout = new FillLayout();

layout.type=SWT.VERTICAL;

layout.marginHeight = 10; // 设置上下补白高度

layout.marginWidth = 20; // 设置左右

layout.spacing = 5;    // 设置控件之间的空隙

shell.setLayout( layout );

显示效果:

21377574_3.jpg

7.3 RowLayout(行列式布局)

RowLayout填充控件时可以折行显示,并且可以使用RowData设置某一个指定控件的大小。

packagewww.swt.com.ch7;

import org.eclipse.swt.SWT;

public class RowLayoutSample {

public static void main(String[] args) {

Display display = new Display();

Shell shell = new Shell(display, SWT.SHELL_TRIM);

RowLayout layout = new RowLayout();

layout.type = SWT.HORIZONTAL;// 设置水平填充

layout.marginLeft = 5;// 左补白

layout.marginTop = 5;// 上补白

layout.marginRight = 5;// 右补白

layout.marginBottom = 5;// 下补白

layout.spacing = 2;// 控件的间隙

layout.wrap = true;// 是否折行显示

layout.pack = false;// false:控件平均分配大小

layout.justify = true;// 是否充满整个一行

shell.setLayout(layout);

new Button(shell, SWT.NONE).setText("B1");

new Button(shell, SWT.NONE).setText("Button2");

new Button(shell, SWT.NONE).setText("Wide Button3");

new Button(shell, SWT.NONE).setText("B4");

shell.layout();

shell.pack();

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch())

display.sleep();

}

display.dispose();

}

}

显示效果:

21377574_4.jpg

设置控件的大小:

//   layout.pack = false;// false:控件平均分配大小

Button b = new Button(shell, SWT.NONE);

b.setText("RowData");

b.setLayoutData(new RowData(100, 30));

显示效果:

21377574_5.jpg

设置是否等宽或等高:fill属性

当以水平方式填充时,fill属性试图使所用控件具有同样高度;当以垂直方式显示时,试图使用所有控件具有同样宽度。

水平填充,设置等高:layout.fill = true;

21377574_6.jpg

垂直填充,设置等宽:layout.fill = true;

21377574_7.jpg

7.4 GridLayout(网格式布局)

使用GridLayout布局,控件将会按照网格的方式进行填充。GridLayout所放置的控件可以有一个关联的布局数据对象GridData。GridLayout的强大功能在于,可以使用GridData为每一个控件设置不同的布局。

import org.eclipse.swt.SWT;

public class GridLayoutSample {

public static void main(String[] args) {

Display display = new Display();

Shell shell = new Shell(display, SWT.SHELL_TRIM);

GridLayout gridLayout = new GridLayout();

gridLayout.numColumns = 3; //设置网格的列数

gridLayout.makeColumnsEqualWidth = true; //设置网格等宽

gridLayout.verticalSpacing = 10;

gridLayout.horizontalSpacing = 10;

shell.setLayout(gridLayout);

new Button(shell, SWT.PUSH).setText("B1");

new Button(shell, SWT.PUSH).setText("Wide Button 2");

new Button(shell, SWT.PUSH).setText("Button 3");

new Button(shell, SWT.PUSH).setText("B4");

new Button(shell, SWT.PUSH).setText("Button 5");

new Button(shell, SWT.PUSH).setText("B6");

//GridData

Button button = new Button(shell, SWT.PUSH);

button.setText("GridData");

button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.GRAB_HORIZONTAL));

Button b1 = new Button(shell, SWT.PUSH);

b1.setText("GridData2");

GridData gridData = new GridData();

//   gridData.horizontalIndent = 20; // 缩进

gridData.horizontalSpan =2; // 水平跨越两个单元格

gridData.horizontalAlignment = SWT.FILL; //充满

b1.setLayoutData(gridData);

Button b2 = new Button(shell, SWT.PUSH);

b2.setText("GridData3");

GridData gridData2 = new GridData();

gridData2.horizontalSpan =2; // 水平跨越两个单元格

gridData2.verticalSpan = 2;   // 垂直跨越两个单元格

gridData2.horizontalAlignment = SWT.FILL; //水平充满

gridData2.verticalAlignment = SWT.FILL;   //垂直充满

gridData2.grabExcessHorizontalSpace = true; //设置水平抢占

gridData2.grabExcessVerticalSpace = true; //设置垂直抢占

gridData2.minimumHeight=100; //最小高度

gridData2.minimumWidth =100; //最小宽度

gridData2.widthHint=100; //设置宽度

gridData2.heightHint=100; //设置高度

b2.setLayoutData(gridData2);

shell.layout();

shell.pack();

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch())

display.sleep();

}

display.dispose();

}

}

注意:不要重用GridData对象。每一个面板(Composite)对象中被GridLayout管理的控件必须有一个唯一的GridData对象。如果在设置布局时一个GridLayout中的控件的GridData为null,就会为它创建一个唯一的GridData对象。

注意:设置了widthHint和heightHint属性后只是在程序刚一运行时才会起作用,随着窗口的改变,会重新计算控件大小。

显示效果:

21377574_8.jpg

去掉下面两行后的效果:

gridData2.grabExcessHorizontalSpace = true; //设置水平抢占

gridData2.grabExcessVerticalSpace = true; //设置垂直抢占

21377574_9.jpg按钮“GridData3”未随着窗口大小调整高度。

样式常量对照表

样式常量 <==> 对应属性值

GRAB_HORIZONTAL <==> grabExcessHorizontalSpace=true

GRAB_VERTICAL <==> grabExcellVerticalSpace=true

HORIZONTAL_ALIGN_BEGINNING   <==> horizontalAlignment=SWT.BEGINNING

HORIZONTAL_ALIGN_CENTER <==> horizontalAlignment=SWT.CENTER

HORIZONTAL_ALIGN_END <==> horizontalAlignment=SWT.END

HORIZONTAL_ALIGN_FILL <==> horizontalAlignment=SWT.FILL

VERTICAL_ALIGN_BEGINNING   <==> verticalAlignment=SWT.BEGINNING

VERTICAL_ALIGN_CENTER <==> verticalAlignment=SWT.CENTER

VERTICAL_ALIGN_END <==> verticalAlignment=SWT.END

VERTICAL_ALIGN_FILL <==> verticalAlignment=SWT.FILL

FILL_BOTH <==> horizontalAlignment=SWT.FILL + verticalAlignment=SWT.FILL

7.5 FormLayout(表格式布局)

FormLayout通过设置FormData四边的附加值(FormAttachment对象)来设置控件的布局。一个附加值让一个控件指定的一边附件到父面板容器类(Composite)的位置或者其他控件上。所以,这种布局可以指定某两个控件的相对位置,并且能随着窗口的改变而改变。

FormAttachment 的使用说明及示例参考:SWT 之 FormAttachment

7.6 StackLayout(堆栈式布局)

StackLayout堆栈式布局类似于选项卡(TabFolder),当前只显示最上方的控件。例如,面板上有10个文本框,面板设置为StackLayout布局,当单击“显示下一个文本框”按钮时,下一个文本框就显示出来,这样面板中始终只有一个文本框,设置最上方显示控件的属性是layout.topControl。

packagewww.swt.com;

import org.eclipse.swt.SWT;

import org.eclipse.swt.custom.StackLayout;

import org.eclipse.swt.layout.GridData;

import org.eclipse.swt.layout.GridLayout;

import org.eclipse.swt.widgets.Button;

import org.eclipse.swt.widgets.Composite;

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Event;

import org.eclipse.swt.widgets.Listener;

import org.eclipse.swt.widgets.Shell;

import org.eclipse.swt.widgets.Text;

public class testStackLayout {

/**

* @param args

*/

public static void main(String[] args) {

Display display = new Display();

Shell shell = new Shell(display);

shell.setLayout(new GridLayout());

// 创建放置文本框的面板

final Composite parent = new Composite(shell, SWT.NONE);

// 设置面板的布局数据

parent.setLayoutData(new GridData(GridData.FILL_BOTH));

// 创建堆栈式布局

final StackLayout layout = new StackLayout();

// 将堆栈式布局应用于模板

parent.setLayout(layout);

// 创建10个文本框

final Text[] textArray = new Text[10];

for (int i = 0; i < textArray.length; i++) {

textArray[i] = new Text(parent, SWT.MULTI);

textArray[i].setText("这是第 " + i + " 个文本框");

}

// 设置堆栈中当前显示的控件

layout.topControl = textArray[0];

Button b = new Button(shell, SWT.PUSH);

b.setText("显示下一个文本框");

// 保存当前显示的文本框的索引值

final int[] index = new int[1];

// 为按钮添加单击事件

b.addListener(SWT.Selection, new Listener() {

@Override

public void handleEvent(Event arg0) {

// 计算出下一个文本框的索引数

index[0] = (index[0] + 1) % textArray.length;

// 设置当前显示的控件

layout.topControl = textArray[index[0]];

// 重新刷新布局

parent.layout();

}

});

shell.setSize(200, 150);

shell.open();

shell.layout();

//   shell.pack();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) {

display.sleep();

}

}

display.dispose();

}

}

显示效果:

21377574_10.jpg 点击按钮后:21377574_11.jpg

7.7 自定义布局管理器

任何布局类都是Lyaout的子类,Layout是一个抽象类,源代码如下:

package org.eclipse.swt.widgets;

import org.eclipse.swt.graphics.*;

public abstract class Layout {

protected abstract Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache);

protected boolean flushCache (Control control) {

return false;

}

protected abstract void layout (Composite composite, boolean flushCache);

}

创建一个自定义的布局类要继承Layout类,并且要实现Layout中的抽象方法。以下代码创建的是一个最简单的自定义类MyLayout:

packagewww.swt.com;

import org.eclipse.swt.graphics.Point;

import org.eclipse.swt.widgets.Composite;

import org.eclipse.swt.widgets.Layout;

public class MyLayout extends Layout {

// 该方法计算面板显示的大小

protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {

return new Point(wHint, hHint);

}

// 设置子控件的位置

protected void layout(Composite composite, boolean flushCache) {

}

}

Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache)方法:该方法是计算布局的大小,也就是按照一定的规则算法计算出最终布局的长和宽,其中wHint和hHint是设置默认的宽和高。例如:当计算出来的长和宽小于默认的宽和高时,就可以使用默认的宽和高。flushCache参数设置是否使用缓存的数据。

void layout(Composite composite, boolean flushCache)方法:该方法是对该面板(参数Composite)中所有的控件(Control)设置显示的具体位置,通常获得该面板中的所有控件的方法是composite.getChildren()。这样就可以根据指定的计算规则来放置每个控件的位置了。

综上所述,创建一个自定义布局关键是实现这两个方法,而具体布局的设置要根据设定的计算方法来实现。

布局计算的常用方法

1. 控件(Control)类中的常用方法

◆ 计算控件合适的大小的方法:Point computeSize(int wHint, int hHint)和Point computeSize(int wHint, int hHint, boolean changed)。例如:

Point point = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);

int width = point.x;

int height = point.y;

◆ 获得控件当前坐标位置的方法:Rectangle getBounds()。例如:

Rectangle rect = control.getBounds();

int left = rect.x;

int right = rect.width;

int top = rect.y;

int bottom = rect.height;

◆ 设置控件位置的方法:setBounds(int x, int y, int width, int height)或setBounds(Rectangle rect)。

2. 面板(Composite)类中的常用方法

◆ 获得面板的大小区域的方法:Rectangle getClientArea()。

◆ 获得所有子控件的方法:Control[] getChildren()。

◆ 获得面板的布局对象:Layout getLayout()。

自定义布局类(BorderLayout)

BorderLayout布局将控件按东、南、西、北、中5个区域放置,每个方向最多只能放置一个控件,随着窗口大小的改变,整个窗口会不断撑大。

(1)创建一个BorderData类,该类设置控件所在位置。

packagewww.swt.com.ch7.testBorderLayout;

import org.eclipse.swt.SWT;

public final class BorderData {

public int region = SWT.CENTER; // 默认为中间

public BorderData() {

}

public BorderData(int region) {

this.region = region;

}

}

(2)编写最重要的BorderLayout类,该类的详细代码如下:

packagewww.swt.com.ch7.testBorderLayout;

import org.eclipse.swt.SWT;

public class BorderLayout extends Layout {

// 定义存放在不同位置的5个控件

private Control north;

private Control south;

private Control east;

private Control west;

private Control center;

@Override

protected Point computeSize(Composite composite, int wHint, int hHint,

boolean flushCache) {

getControls(composite);

// 定义面板的宽和高

int width = 0, height = 0;

// 计算面板的宽度

width += west == null ? 0 : getSize(west, flushCache).x;

width += east == null ? 0 : getSize(east, flushCache).x;

width += center == null ? 0 : getSize(center, flushCache).x;

// 如果上部和下部都有控件,则宽取较大值

if (north != null) {

Point pt = getSize(north, flushCache);

width = Math.max(width, pt.x);

}

if (south != null) {

Point pt = getSize(south, flushCache);

width = Math.max(width, pt.x);

}

// 计算面板的高度

height += north == null ? 0 : getSize(north, flushCache).y;

height += south == null ? 0 : getSize(south, flushCache).y;

int heightOther = center == null ? 0 : getSize(center, flushCache).y;

if (west != null) {

Point pt = getSize(west, flushCache);

heightOther = Math.max(heightOther, pt.y);

}

if (east != null) {

Point pt = getSize(east, flushCache);

heightOther = Math.max(heightOther, pt.y);

}

height += heightOther;

// 计算的宽和高与默认的宽和高作比较,返回之中较大的

return new Point(Math.max(width, wHint), Math.max(height, hHint));

}

@Override

protected void layout(Composite composite, boolean flushCache) {

getControls(composite);

// 获得当前面板可显示的区域

Rectangle rect = composite.getClientArea();

int left = rect.x, right = rect.width, top = rect.y, bottom = rect.height;

// 将各个控件放置到面板中

if (north != null) {

Point pt = getSize(north, flushCache);

north.setBounds(left, top, rect.width, pt.y);

top += pt.y;

}

if (south != null) {

Point pt = getSize(south, flushCache);

south.setBounds(left, rect.height - pt.y, rect.width, pt.y);

bottom -= pt.y;

}

if (east != null) {

Point pt = getSize(east, flushCache);

east.setBounds(rect.width - pt.x, top, pt.x, (bottom - top));

right -= pt.x;

}

if (west != null) {

Point pt = getSize(west, flushCache);

west.setBounds(left, top, pt.x, (bottom - top));

left += pt.x;

}

if (center != null) {

center.setBounds(left, top, (right - left), (bottom - top));

}

}

// 计算某一控件当前的大小,长和宽

protected Point getSize(Control control, boolean flushCache) {

return control.computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache);

}

// 设置该类中每个位置控件的属性的方法

protected void getControls(Composite composite) {

// 获得当前面板中所有的控件对象

Control[] children = composite.getChildren();

// 循环所有控件,并将每个控件所放的位置对号入座

for (int i = 0; i < children.length; i++) {

Control child = children[i];

BorderData borderData = (BorderData) child.getLayoutData();

if (borderData.region == SWT.TOP) {

north = child;

} else if (borderData.region == SWT.BOTTOM) {

south = child;

} else if (borderData.region == SWT.RIGHT) {

east = child;

} else if (borderData.region == SWT.LEFT) {

west = child;

} else {

center = child;

}

}

}

}(3)最后创建一个测试类:

packagewww.swt.com.ch7.testBorderLayout;

import org.eclipse.swt.SWT;

import org.eclipse.swt.widgets.Button;

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Shell;

import org.eclipse.swt.widgets.Text;

public class TestBorderLayout {

/**

* @param args

*/

public static void main(String[] args) {

Display display = new Display();

Shell shell = new Shell(display);

shell.setSize(200, 150);

shell.setLayout(new BorderLayout());

Button buttonWest = new Button(shell, SWT.PUSH);

buttonWest.setText("左");

buttonWest.setLayoutData(new BorderData(SWT.LEFT));

Button buttonEast = new Button(shell, SWT.PUSH);

buttonEast.setText("右");

buttonEast.setLayoutData(new BorderData(SWT.RIGHT));

Button buttonNorth = new Button(shell, SWT.PUSH);

buttonNorth.setText("上");

buttonNorth.setLayoutData(new BorderData(SWT.TOP));

Button buttonSouth = new Button(shell, SWT.PUSH);

buttonSouth.setText("下");

buttonSouth.setLayoutData(new BorderData(SWT.BOTTOM));

Text text = new Text(shell, SWT.MULTI);

text.setText("中间");

text.setLayoutData(new BorderData());

shell.pack();

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) {

display.sleep();

}

}

display.dispose();

}

}

显示效果:

21377574_12.jpg 拖放后的效果:21377574_13.jpg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值