《Eclipse SWT/JFACE 核心应用》 清华大学出版社 6 面板容器类
所有容器类的父类:Composite类。
容器类:分组框(Group)、选项卡(TabFolder)、自定义选项卡(CTabFolder)、分割窗框(SashForm)、自定义分割框(CBanner)、滚动面板(ScrolledComposite)和ViewForm。
6.1 面板类(Composite)
面板类的样式:
SWT.NONE:没有边框的面板
SWT.BORDER:带有边框的面板
SWT.NO_RADIO_GROUP:对于一组单选按钮,可以同时选中多个按钮
面板类的常用方法:
获得面板中所有控件的方法:Control[] getChildren()
获得面板的父面板:Composite getParent()
设置面板布局:setLayout(Layout)
刷新布局:layout()
6.2 分组框(Group)
Group group = new Group(shell, SWT.SHADOW_ETCHED_OUT);
group.setText("分组框");
group.setLayout(new RowLayout());
Group类可以选择的样式常量有:SWT.SHADOW_ETCHED_IN、SWT.SHADOW_ETCHED_OUT、SWT.SHADOW_IN、SWT.SHADOW_OUT、SWT.SHADOW_NONE。
6.3 选项卡(TabFolder)
final TabFolder tabFolder = new TabFolder(shell,
SWT.TOP);
tabFolder.setLayout(new FillLayout());
for (int i = 0; i < 4; i++) {
TabItem item = new TabItem(tabFolder, SWT.NONE);
item.setText("选项卡 " + i);
Text t = new Text(tabFolder, SWT.MULTI);
t.setText("这是第 " + i + " 页");
item.setControl(t);
}
tabFolder.pack();
显示效果:
选项卡的位置放在底部:
final TabFolder tabFolder = new TabFolder(shell, SWT.BOTTOM);
显示效果:
选项卡的常用方法:
设置选项卡图标:setImage()
获得指定索引的选项卡:TabItem getItem(index)
获得选项卡的总数:getItemCount()
获得选项卡数组:getItems()
获得当前选中的选项卡:getSelection()
获得当前选中选项卡的索引值:getSelectionIndex()
查找是否存在指定的选项:indexOf(TabItem item)
设置选中指定的选项卡:setSelection()
6.4 自定义选项卡(CTabFolder)
CTabFolder由多个CTabItem对应。
package www.swt.com;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class testCTabFolder {
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(300, 200);
shell.setLayout(new FillLayout());
shell.setText("自定义选项卡");
// 选项卡样式:带有“关闭”按钮、带有边框
final CTabFolder tabFolder = new CTabFolder(shell, SWT.TOP | SWT.CLOSE | SWT.BORDER);
tabFolder.setTabHeight(20);
tabFolder.setLayout(new FillLayout());
tabFolder.marginHeight = 10;
tabFolder.marginWidth = 10;
// 显示“最大化、最小化”按钮
tabFolder.setMaximizeVisible(true);
tabFolder.setMinimizeVisible(true);
for (int i = 0; i < 4; i++) {
CTabItem item = new CTabItem(tabFolder, SWT.NONE);
item.setText("选项卡 " + i);
Text t = new Text(tabFolder, SWT.MULTI);
t.setBounds(5, 5, 150, 150);
t.setText("这是第 " + i + " 页");
item.setControl(t);
}
tabFolder.pack();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
显示效果:
// 设置单一的前景色和背景色
tabFolder.setSelectionForeground(display.getSystemColor(SWT.COLOR_WHITE));
tabFolder.setSelectionBackground(display.getSystemColor(SWT.COLOR_BLUE));
显示效果:
tabFolder.setSelectionForeground(display.getSystemColor(SWT.COLOR_WHITE));
// 设置渐变的背景色
Color[] color = new Color[4];
color[0] = display.getSystemColor(SWT.COLOR_DARK_BLUE);
color[1] = display.getSystemColor(SWT.COLOR_BLUE);
color[2] = display.getSystemColor(SWT.COLOR_WHITE);
color[3] = display.getSystemColor(SWT.COLOR_WHITE);
int[] intArray = new int[] {25, 50, 100};
tabFolder.setSelectionBackground(color, intArray);
显示效果:
// 设置选项卡背景图片
tabFolder.setSelectionBackground(new Image(display, "F:\\background.gif"));
显示效果:
若同时设置背景颜色和背景图片,只显示背景图片,而设置的颜色不起作用。
仿Eclipse编辑区的选项卡:
package www.swt.com.ch6;
import org.eclipse.swt.SWT;
public class EclipseTabSample {
public static void main(String[] args) {
Display display = new Display();
// 创建图片对象,该图片对象设置选项卡上的图标
Image image = new Image(
display,
"F:\\samples.gif");
final Shell shell = new Shell(display);
shell.setText("仿Eclipse编辑区的选项卡");
shell.setLayout(new GridLayout());
// 创建自定义选项卡对象
final CTabFolder folder = new CTabFolder(shell, SWT.BORDER);
// 设置选项卡的布局,通过布局的设置呈现出最大化和最小化的外观
folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
// 设置复杂的选项卡,也就是带有圆角的选项卡标签
folder.setSimple(false);
// 设置未选中标签,图标和关闭按钮的状态
folder.setUnselectedImageVisible(true);
folder.setUnselectedCloseVisible(true);
// 设置前景色和背景色
folder.setSelectionForeground(display.getSystemColor(SWT.COLOR_WHITE));
folder.setSelectionBackground(display.getSystemColor(SWT.COLOR_BLUE));
// 显示最大化和最小化按钮
folder.setMinimizeVisible(true);
folder.setMaximizeVisible(true);
// 创建选项卡标签对象
for (int i = 1; i < 5; i++) {
CTabItem item = new CTabItem(folder, SWT.CLOSE);
item.setText("选项卡 " + i);
item.setImage(image);
// 每个选项卡中放置一个Text文本框
Text text = new Text(folder, SWT.MULTI | SWT.V_SCROLL
| SWT.H_SCROLL);
// 文本框中的文字带有\n表示,显示时换到下一行
text.setText("这是第" + i + "页:\n该选项卡仿照Eclipse设计\n最大化和最小化按钮都可以使用");
item.setControl(text);
}
// 注册选项卡事件
folder.addCTabFolder2Listener(new CTabFolder2Adapter() {
// 当单击最小化按钮时触发的事件
public void minimize(CTabFolderEvent event) {
// 设置选项卡的状态为最小化,选项卡的状态决定显示在右上角的窗口按钮
folder.setMinimized(true);
// 改变选项卡的布局,呈现最小化状态
folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
false));
// 刷新布局,否则重新设置的布局将不起作用
shell.layout(true);
}
// 当单击最大化按钮时触发的事件
public void maximize(CTabFolderEvent event) {
folder.setMaximized(true);
folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
true));
shell.layout(true);
}
// 当单击还原按钮时触发的事件
public void restore(CTabFolderEvent event) {
folder.setMinimized(false);
folder.setMaximized(false);
folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
false));
shell.layout(true);
}
});
shell.setSize(300, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// 释放图片资源
image.dispose();
display.dispose();
}
}
显示效果:
实现该程序的关键点:
1. folder.setSimple(false):选项卡的外观以圆角形式显示。
2. “最大化”、“最小化”按钮事件的处理:
folder.addCTabFolder2Listener(new CTabFolder2Adapter() {
// 当单击最小化按钮时触发的事件
public void minimize(CTabFolderEvent event) {
}
// 当单击最大化按钮时触发的事件
public void maximize(CTabFolderEvent event) {
}
// 当单击还原按钮时触发的事件
public void restore(CTabFolderEvent event) {
}
});
3. 最大化和最小化界面的外观的实现原理
最大化和最小化界面的改变是通过改变布局来实现的。
4. 选项卡的有关状态:
是否最小化:getMinimized()
是否最大化:getMaxmized()
设置是否最小化:setMinimized()
设置是否最大化:setMaxmized()
限制选项卡文字的长度
// 限制选项卡文字的长度
folder.setMinimumCharacters(2);
显示效果:
设置右上角控件
除了“最大化”和“最小化”按钮外,还可以将一个控件设置在右上角。通常情况下,放置在右上角的控件可以是“关闭”按钮或者一个菜单。
// 设置右上角的控件
Button button = new Button(tabFolder, SWT.ARROW | SWT.RIGHT);
tabFolder.setTopRight(button);
显示效果:
设置按钮充满整个右上角区域:
// 设置右上角的控件
Button button = new Button(tabFolder, SWT.ARROW | SWT.RIGHT);
tabFolder.setTopRight(button, SWT.FILL);
如果此时想取消右上角的控件,只需设置控件为“null”即可:
tabFolder.setTopRight(null);
自定义选项的常用方法:
设置是否显示边框:setBorderVisible()
设置选项卡字体:setFont()
设置选项卡高度:setTabHeight()
设置选项卡的位置:setTabPosition(),默认为显示在上方。SWT.BOTTOM:显示在下方,SWT.TOP:显示在上方。
6.5 分割窗框(SashForm)
分割窗框将屏幕的区域分成几个部分,并且能够拖动窗框来改变窗口的大小。
package www.swt.com.ch6;
import org.eclipse.swt.SWT;
public class SashFormSample {
public static void main(String[] args) {
final Display display = new Display ();
Shell shell = new Shell(display);
shell.setLayout (new FillLayout());
shell.setText("SashForm");
//创建窗框对象,设置样式为水平排列
SashForm form = new SashForm(shell,SWT.HORIZONTAL|SWT.BORDER);
form.setLayout(new FillLayout());
//创建窗口1的面板
Composite child1 = new Composite(form,SWT.NONE);
child1.setLayout(new FillLayout());
new Text(child1,SWT.MULTI).setText("窗口1");
//创建窗口2的面板
Composite child2 = new Composite(form,SWT.NONE);
child2.setLayout(new FillLayout());
new Text(child2,SWT.MULTI).setText("窗口2");
//设置初始状态两个面板所占的比例
form.setWeights(new int[] {30,70});
//form.setMaximizedControl( child1 );
//form.setMaximizedControl( null );
shell.setSize( 200,150);
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
}
显示效果:
分割窗框的样式:
平滑外观的窗框:
SashForm form = new SashForm(shell,SWT.HORIZONTAL|SWT.SMOOTH);
显示效果:
将窗口放置的位置改为垂直放置:
SashForm form = new SashForm(shell,SWT.VERTICAL|SWT.SMOOTH);
显示效果:
设置窗框显示的比例:
form.setWeights(new int[]{30, 30, 40}); // 三个窗口从左到右所占的空间比例分别为30%、30%、40%
设置控件填充整个form:
form.setMaximizedControl(folder);
将最大化显示的控件置为null:
form.setMaximizedControl(null);
6.6 自定义分割框(CBanner)
自定义分割框有3个控件,分别放在窗口的左侧(left)、右侧(right)和底部(bottom)。左侧和右侧的窗口可以改变大小,但底部的大小是不可以变化的。
package www.swt.com.ch6;
import org.eclipse.swt.SWT;
public class CBannerSample {
public static void main(String[] args) {
final Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("CBanner");
// 创建CBanner对象
CBanner banner = new CBanner(shell, SWT.BORDER);
banner.setLayout(new FillLayout());
// 创建三个面板,分别放置到左侧,右侧和底部
Composite left = new Composite(banner, SWT.NONE);
left.setLayout(new FillLayout());
new Text(left, SWT.MULTI).setText("左侧");
Composite right = new Composite(banner, SWT.NONE);
right.setLayout(new FillLayout());
new Text(right, SWT.MULTI).setText("右侧");
Composite bottom = new Composite(banner, SWT.NONE);
bottom.setLayout(new FillLayout());
new Text(bottom, SWT.MULTI).setText("下部");
// 设置左侧的控件
banner.setLeft(left);
// 设置右侧的控件
banner.setRight(right);
// 设置底部的控件
banner.setBottom(bottom);
banner.setSimple(false);
shell.setSize(200, 150);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
显示效果:
banner.setSimple(false); // 改变左右窗框分割线的外观
6.7 滚动面板(ScrolledComposite)
滚动面板:带有垂直滚动条和水平滚动条的面板。
package www.swt.com.ch6;
import org.eclipse.swt.SWT;
public class ScrolledCompositeSample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("ScrolledComposite");
// 创建一个滚动面板对象
final ScrolledComposite sc = new ScrolledComposite(shell, SWT.H_SCROLL
| SWT.V_SCROLL | SWT.BORDER);
// 创建一个普通的面板
final Composite c = new Composite(sc, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 4;
c.setLayout(layout);
for (int i = 0; i < 20; i++) {
Button bt = new Button(c, SWT.PUSH);
bt.setText("按钮" + i);
c.setSize(c.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
// 将普通面板设置为受控的滚动面板
sc.setContent(c);
// sc.setAlwaysShowScrollBars( true );
// sc.setExpandHorizontal( true );
shell.setSize(200, 150);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
显示效果:
设置是否总是显示滚动条:setAlwaysShowScrollBars()
设置水平滚动条是否显示:setExpandHorizontal()
设置垂直滚动条是否显示:setExpandVertical()
设置最小显示滚动条的高度:setMinHeight()
设置最小显示滚动条的宽度:setMinWidth()
设置最小显示滚动条的高度和宽度:setMinSize(),只有当设置了setExpandVertical(true)和setExpandHorizontal(true)后才起作用。
《Eclipse SWT/JFACE 核心应用》 清华大学出版社 7 SWT布局管理器
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):
垂直填充(SWT.VERTICAL):
设置四周补白:
FillLayout layout = new FillLayout();
layout.type=SWT.VERTICAL;
layout.marginHeight = 10; // 设置上下补白高度
layout.marginWidth = 20; // 设置左右
layout.spacing = 5; // 设置控件之间的空隙
shell.setLayout( layout );
显示效果:
7.3 RowLayout(行列式布局)
RowLayout填充控件时可以折行显示,并且可以使用RowData设置某一个指定控件的大小。
package www.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();
}
}
显示效果:
设置控件的大小:
// layout.pack = false;// false:控件平均分配大小
Button b = new Button(shell, SWT.NONE);
b.setText("RowData");
b.setLayoutData(new RowData(100, 30));
显示效果:
设置是否等宽或等高:fill属性
当以水平方式填充时,fill属性试图使所用控件具有同样高度;当以垂直方式显示时,试图使用所有控件具有同样宽度。
水平填充,设置等高:layout.fill = true;
垂直填充,设置等宽:layout.fill = true;
7.4 GridLayout(网格式布局)
使用GridLayout布局,控件将会按照网格的方式进行填充。GridLayout所放置的控件可以有一个关联的布局数据对象GridData。GridLayout的强大功能在于,可以使用GridData为每一个控件设置不同的布局。
package www.swt.com.ch7;
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属性后只是在程序刚一运行时才会起作用,随着窗口的改变,会重新计算控件大小。
显示效果:
去掉下面两行后的效果:
gridData2.grabExcessHorizontalSpace = true; //设置水平抢占
gridData2.grabExcessVerticalSpace = true; //设置垂直抢占
按钮“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。
package www.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();
}
}
显示效果:
点击按钮后:
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:
package www.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类,该类设置控件所在位置。
package www.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类,该类的详细代码如下:
package www.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)最后创建一个测试类:
package www.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();
}
}
显示效果:
拖放后的效果: