使用SWT中的Control UI和GridLayout实现类似eclipse preferences 窗口的布局
最近在学习和研究eclipse插件的开发, 从SWT 框架 入手. 把SWT的窗口小部件, 容器, 布局方式梳理了一下, 写出了一些比较综合的包含各种窗口小部 件的 布局 案例, 下面是一个比较完整的DEMO. 使用SWT中的Control UI和GridLayout实现类似eclipse preferences 窗口的布局. 当然, 因为把重点放在了各种窗口 部件和GridLayout布局方式的使用上, 对于各种用户操作事件的监听, 只是简单地进行了打印或显示; 而对于程序性能方面及代码逻辑的合理性, 也有待改进.
下面是程序运行时的画面:
下面是程序运行的代码(为了节省篇幅, 去掉了import语句, 在eclipse中可用快捷键 ctrl + shift + o 导入org.eclipse.swt相关的包):
public class GridLayoutAndWidgetsDemo {
static Display display;
static Shell shell;
static GridLayout gridLayout;
static Composite composite; // Composite容器,都设置为GridLayout布局
// 每个GridData都必须有单独的实例,几个子组件不能够共用同一个GridData
// (即使几个组件有相同属性的GridData也必须新建几个实例)。
static GridData gridData;
// 左侧栏元素
static Text searchText;
static Tree tree;
// 右侧栏元素
static Label titleLabel;
static TabFolder tabFolder;
// 第一个tab里面的元素
static Canvas drawImage;
static Button buttonAddImage;
static Button buttonRemoveImage;
static Image image;
// 第二个tab里面的元素
static Table tableForTab2;
// 第三个tab里面的元素
static Combo comboForTab3;
static Label labelForTab3;
// 第四个tab里面的元素
static Group groupForTab4; // Group容器,设置为GridLayout布局
static List listForTab4;
// 右下角的关闭按钮
static Button buttonClose;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
display = new Display();
shell = new Shell(display);
shell.setText("Preferences");
gridLayout = new GridLayout();
gridLayout.numColumns = 2; // 设置总体布局,分为两列
shell.setLayout(gridLayout);
// 用Composite来布局搜索输入框和树组件
composite = new Composite(shell, SWT.BORDER);
gridLayout = new GridLayout();
gridLayout.numColumns = 1;
composite.setLayout(gridLayout);
// 设置第一个cell纵向填充及占两行
gridData = new GridData(GridData.FILL_VERTICAL);
gridData.verticalSpan = 2;
composite.setLayoutData(gridData);
// 在第二列显示第一列操作对应信息的Label
titleLabel = new Label(shell, SWT.LEFT | SWT.SINGLE);
gridData = new GridData();
// 需要设置默认宽度才会显示内容
gridData.widthHint = 105;
titleLabel.setLayoutData(gridData);
searchText = new Text(composite, SWT.SINGLE | SWT.BORDER);
// 设置水平填充父容器
searchText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// 设置只能输入数值
searchText.addVerifyListener(new VerifyListener() {
public void verifyText(VerifyEvent event) { // 当event.doit为false时取消操作
event.doit = event.text.length() == 0
|| Character.isDigit(event.text.charAt(0));
}
});
searchText.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.character == SWT.CR) { // 监听回车按下事件
titleLabel.setText(searchText.getText());
}
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
});
tree = new Tree(composite, SWT.SINGLE);
gridData = new GridData(GridData.FILL_VERTICAL);
tree.setLayoutData(gridData);
for (int i = 1; i < 4; i++) {
TreeItem grandParent = new TreeItem(tree, 0);
grandParent.setText("Grand Parent - " + i);
for (int j = 1; j < 4; j++) {
TreeItem parent = new TreeItem(grandParent, 0);
parent.setText("Parent - " + j);
for (int k = 1; k < 4; k++) {
TreeItem child = new TreeItem(parent, 0);
child.setText("Child - " + k);
}
}
}
tree.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
TreeItem[] selected = tree.getSelection();
if (selected.length > 0) {
titleLabel.setText(selected[0].getText());
}
}
});
// 用Composite来布局详细信息栏
composite = new Composite(shell, SWT.BORDER);
gridLayout = new GridLayout();
gridLayout.numColumns = 1;
composite.setLayout(gridLayout);
// 设置纵向和横向都填充
gridData = new GridData(GridData.FILL_HORIZONTAL
| GridData.FILL_VERTICAL);
composite.setLayoutData(gridData);
tabFolder = new TabFolder(composite, SWT.BORDER);
gridData = new GridData(GridData.FILL_HORIZONTAL
| GridData.FILL_VERTICAL);
tabFolder.setLayoutData(gridData);
// 生成4个Tab:Tab1 Tab2 Tab3 Tab4
for (int i = 1; i < 5; i++) {
TabItem tabItem = new TabItem(tabFolder, SWT.NULL);
tabItem.setText("Tab " + i);
Composite compositeForTab = new Composite(tabFolder, SWT.NULL);
gridLayout = new GridLayout();
gridLayout.numColumns = 1;
compositeForTab.setLayout(gridLayout);
compositeForTab.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
| GridData.FILL_VERTICAL));
tabItem.setControl(compositeForTab);
if (i == 1) {
buttonAddImage = new Button(compositeForTab, SWT.PUSH);
buttonAddImage.setText("addImage");
buttonAddImage.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
String fileName = new FileDialog(shell).open();
if (fileName != null) {
image = new Image(display, fileName);
drawImage.redraw();
}
}
});
buttonRemoveImage = new Button(compositeForTab, SWT.PUSH);
buttonRemoveImage.setText("removeImage");
buttonRemoveImage.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
if (image != null) {
image.dispose();
image = null;
drawImage.redraw();
}
}
});
drawImage = new Canvas(compositeForTab, SWT.BORDER);
gridData = new GridData(GridData.FILL_HORIZONTAL
| gridData.FILL_VERTICAL);
drawImage.setLayoutData(gridData);
// 添加画布的重画事件,即redraw()
drawImage.addPaintListener(new PaintListener() {
public void paintControl(final PaintEvent event) {
if (image != null) {
event.gc.drawImage(image, 0, 0);
}
}
});
} else if (i == 2) {
tableForTab2 = new Table(compositeForTab, SWT.SINGLE
| SWT.BORDER | SWT.CHECK);
tableForTab2.setLayoutData(new GridData(
GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
tableForTab2.setHeaderVisible(true);
tableForTab2.setLinesVisible(true);
TableColumn column1 = new TableColumn(tableForTab2, SWT.NULL);
column1.setText("Name");
column1.setWidth(60);
TableColumn column2 = new TableColumn(tableForTab2, SWT.NULL);
column2.setText("Age");
column2.pack();
TableItem item1 = new TableItem(tableForTab2, SWT.NULL);
item1.setText(new String[] { "Dan", "43" });
TableItem item2 = new TableItem(tableForTab2, SWT.NULL);
item2.setText(new String[] { "Eric", "44" });
tableForTab2.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
TableItem[] selected = tableForTab2.getSelection();
if (selected.length > 0) {
System.out.println("Name: "
+ selected[0].getText(0));
System.out.println("Age: " + selected[0].getText(1));
}
}
});
} else if (i == 3) {
comboForTab3 = new Combo(compositeForTab, SWT.READ_ONLY);
comboForTab3.setLayoutData(new GridData(
GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
comboForTab3.setItems(new String[] { "FirstCombo1",
"SecondCombo1", "ThirdCombo1" });
comboForTab3.setText("FirstCombo111"); // 因为设置了SWT.READ_ONLY,所以本句不起作用
labelForTab3 = new Label(compositeForTab, SWT.CENTER);
labelForTab3.setLayoutData(new GridData(
GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
comboForTab3.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
labelForTab3.setText("Selected: "
+ comboForTab3.getText());
}
});
} else {
groupForTab4 = new Group(compositeForTab, SWT.NULL);
groupForTab4.setText("My Group");
gridLayout = new GridLayout();
gridLayout.numColumns = 1;
groupForTab4.setLayout(gridLayout);
groupForTab4.setLayoutData(new GridData(
GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
listForTab4 = new List(groupForTab4, SWT.SINGLE);
listForTab4.setLayoutData(new GridData(GridData.FILL_VERTICAL));
listForTab4.setBackground(display
.getSystemColor(SWT.COLOR_GRAY));
listForTab4.setItems(new String[] { "FirstListItem",
"SecondListItem", "ThirdListItem" });
listForTab4.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
String[] selected = listForTab4.getSelection();
if (selected.length > 0)
System.out.println("Selected: " + selected[0]);
}
});
}
}
buttonClose = new Button(shell, SWT.PUSH);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_END
| GridData.VERTICAL_ALIGN_CENTER);
gridData.horizontalSpan = 2;
buttonClose.setLayoutData(gridData);
buttonClose.setText("close");
buttonClose.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
// TODO Auto-generated method stub
shell.dispose();
}
});
// 窗口大小根据内容调整
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
// 这句话的作用:可以运行两个程序窗口(一个注释掉display.sleep(),一个不注释),然后在任务管理器的进程栏中比较占用cpu资源的不同
display.sleep();
}
}
// 释放平台资源
display.dispose();
}
}
补充说明:
在shell中, 设置的布局方式是GridLayout. Grid布局即为格子布局, 默认是从左往右,从上往下的顺序将"格子"填满. 此外, 可以用 GridData.horizontalSpan (设置一个格子占多少列, 假如赋值为n, 就是说当前这个格子占了n列格子的位置) 或 GridData.verticalSpan (设置一个格子占多少行, 假如赋值为n, 就是说当前这个格子占了n行格子的位置) , 设置当前格子所占的列数或行数;
对于容器, 如本列中的 Composite 和 Group 等等, 同样需要设置为GridLayout的布局方式.