JAVA.SWT/JFace: 面板容器类/SWT布局管理器

《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();
}
}

显示效果:
拖放后的效果:


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值