SWT学习笔记!
1,SWT/JFace 与AWT/SWING 区别是?
java的标准图形 API : AWT/SWING 一直是被后人诟病的, 用它写的页面不够完美, 页面响应速度还慢。后来出现的Eclipse 的SWT/JFace 图形 API 彻底改变了这一状况。主要原因是: SWT/JFace 与AWT/SWING 在实现上有很大的不同, AWT/SWING 是模拟本机窗口组件, 而 SWT/JFace 则是直接调用本机窗口组件,当本机没有所需组件时才进行模拟。
2,SWT/JFace 的缺点是?
它没有java的跨平台的特性,每个OS要用eclipse,都需要重新移植一次SWT/JFace ,这也是SWT/JFace 最具争议的地方。不过因为SWT/JFace 已经移植到了几个主流的OS上了,所以这已经不再是什么严重的问题了。
3,eclipse可以用来开发JAVA、C、C++等
eclipse有极为强大的集成开发环境,它集成了CVS, JUnit, Ant, 并且强大的代码重构功能独步江湖、无人能及。eclipse的安装包集成了java开发环境的插件、JDT、所以、它是默认的java开发工具、但它不仅对java开发、给它装上C/C++的插件、就用可以用开发C、C++了。
4、eclipse常用插件的安装、以及下载地址。
eclipse的插件安装其实很简单、只需要将安装的插件包拷贝到eclipse下面的plugins就ok了。
SWT Designer 是一个很好的eclipse的SWT 界面开发插件包、SWT Designer支持、界面组件拖拉操作
官方网站地址: http://www.swt-designer.com
MyEclipse:j2ee开发插件、支持jsp、ejb、数据库操作。官方网站地址:http://www.myeclipseide.com/
lomboz: 是和MyEclipse 同类型的插件、不过 MyEclipse 是收费的、 lomboz免费 这样的插件有很多、这里就不详细介绍了。
5, SWT/JFace的简单介绍!
SWT/JFace 有多强大,看看eclipse3.0(and以后版本),就可以清楚的知道了。 首先, JFace是为了方便开发SWT程序,在SWT基础上创建的一个更易用,功能强大的图形包。然而, JFace并不能完全覆盖SWT的所有功能,所以,编程时,JFace和SWT都会被用到,但是一般来说能用JFace组件,就最好不要用SWT的。
6, SWT中的包!
①org.eclipse.swt.widgets
最常用的组件基本都在这个包里,如:button,text,label,combo等,其中两个最重要的组件当数,shell 和 composite;shell相当于应用程序的主窗口,composite,相当于SWING中的panel对象,时容纳组件的容器。
②org.eclipse.swt.layout
主要的界面布局方式在该包中。SWT对组件的布局也采用了AWT/SWING中的Layout 和 Layout Data 结合的方式
③org.eclipse.swt.custom
对一些基本图形组件的扩展在该包中。例如:其中的CLabel就是对标准Label组件的扩展,在CLabel上可以同时加入文字和图片。在该包中还有一个新的布局方式StackLayout。
④org.eclipse.swt.event
SWT采用和AWT/SWING一样的时间模型,在包中,可以找到事件监听类和相应的事件对象。例如:鼠标事件监听器MouseListener,MouseMoveListener等,以及对应的事件对象MouseEvent。
⑤org.eclipse.swt.graphics
该包中,包含针对图片,光标,字体和绘图API。例如:可通过IMAGE类来调用系统中不同类型的图片。
⑥org.eclipse.swt.ole.win32
对不同平台,SWT有一些针对性的API。例如,在Windows平台,可以通过该包很容易的调用ole组件,这使得SWT程序也可以内嵌IE浏览器或Word,Excel等程序。
eclipse学习笔记!(2) ----- SWT Designer 概述收藏
SWT Designer是优秀的SWT/JFace开发辅助工具, 以下通过写一个Hello World的小程序来简单了解下SWT!
首先从官方网站下载http://www.swt-designer.com,之后,把对应的文件拷贝到Eclipse目录下,这时,在Eclipse的windows的首选项里面,就可以看到designer了,点击注册,通过注册机完成注册!
然后新建项目时候,选择designer下面的 SWT/JFace java project , 项目名字右键 new other ... designer... Swt...Application Window 选项新建一个第3项 main 主函数的类, 然后就可以运行这个类了。生成的代码如下:
package src;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class HelloWorld ...{
/** *//**
* Launch the application
* @param args
*/
public static void main(String[] args) ...{
//display负责管理事件循环和控制UI线程和其他线程之间的通信
final Display display = Display.getDefault();
final Shell shell = new Shell(); //SHELL是程序的主窗口
shell.setSize(500, 375); //主窗口大小
shell.setText("SWT Application");//主窗口标题
//
shell.open();
shell.layout();
while (!shell.isDisposed()) ...{ //如果,主窗口没有关闭,则一直循环
if (!display.readAndDispatch())//如果DISPLAY不忙
display.sleep(); //DISPLAY休眠
}
}
}
从这个代码可以看到,创建一个典型的SWT应用程序需要以下的步骤:
· 创建一个Display
· 创建一个或多个Shell
· 设置SHELL的布局
· 创建Shell中的组件(以上代码中没有组件,只有一个主窗口,run时候就可以看到一个空的窗口)
· 用open()方法打开Shell窗口
· 写一个事件转发循环
· 销毁Display。
下面,进行窗口中组件的添加, 首先, 把视图切换到designer项,选择SWT Controls分类下的text 组件,放入窗口中,然后对这个组件的属性设置中的 text 设置为 HelloWorld 。 (其他的属性都可以根据自己的情况来设定) 但是 SWT Designer 还无法完成所有的界面设计工作,所以,界面开发中,仍然是以代码设计为主的, 另外 SWT Designer 还不是狠稳定, 界面加入太多的组件, 或频繁的添加删除组件,都有可能造成内存耗尽而死机。
eclipse学习笔记!(3) ----- SWT Designer 下 SWT/JFace 事件的四种写法以及常用的事件收藏
SWT/JFace 事件的四种写法
SWT 的事件模型和 JAVA 标准的 AWT 基本一样的。下面将按照,事件的四种写法来实现它。下面的代码都是和上一个学习笔记里的小例子变化来的。
· 匿名内部类写法
在原来代码行"HelloWorldText = new Text(shell, SWT.BORDER);"下面插入如下的代码:
HelloWorldText.addMouseListener(new MouseAdapter()...{
public void mouseDoubleClick(MouseEvent e) ...{
MessageDialog.openInformation(null,"","Hello world");
}
});
new MouseAdapter(); 就是一个匿名内部类。我们建立了一个继承于MouseAdapter的类,但并没有给这个类命名,并且没有用通常的写法,而是直接在HelloWorldText.addMouseListener()中,写下了这个类的代码,这就是所谓的匿名内部类。
缺点:
1. 由于事件处理,代码会随着组件一起分散到代码中的各个部分,不集中,导致阅读和维护的不便。
2. 各事件的处理全部由嵌套的程序块组成,视觉上很乱,如果事件处理代码很长,也会导致阅读和维护不便。
3. 当菜单栏,工具栏等也需要处理相同的用户行为时,无法重用事件中的处理代码,导致代码不够简洁。
· 命名内部类写法
事件代码使用命名内部类的方式,可以解决匿名内部类的存在的问题, 首先,事件处理代码都集中在一起,并具有有意义的名字,程序容易阅读和维护;另外单个事件的处理程序也可以被工具栏,菜单栏等重用。代码如下:
public class HelloWorld ...{
private static Text HelloWorldText;
public static void main(String[] args) ...{
... ...
HelloWorldText = new Text(shell, SWT.BORDER);
HelloWorldText.addMouseListener(new MyMouseDoubleClick());//引用定义的类
... ...
}
// 定义一个匿名内部类
private static final class MyMouseDoubleClick extends MouseAdapter...{
public void mouseDoubleClick(MouseEvent e) ...{
MessageDialog.openInformation(null,"","Hello ... ai wo , ni shi wo de !!!");
}
}
}
· 外部类写法
这种写法和命名内部类有些相似,只不过是将MyMouseDoubleClick类从HelloWorld.java 中拿出去,单独写成一个类文件。代码和命名内部类的相同,我就不重复了。
· 实现监听接口的写法
将HelloWorld 类实现 MouseListener 接口,这样类本身就成了一个监听器,使得加入监听器的代码可以更加的简洁,这种方式适合加入监听器的组件较多,并且要求监听器的事件处理代码可以被组件共用。
实现MouseListener接口要写的事件方法多一些,没有用到的可以为空实现。如果继承MouseListener 接口的适配器MouseAdapter, 则只写需要的方法就可以了。另外需要注意的是,只有接口才有多继承的特性,所以,如果HelloWorld已经是某个类的子类了,就只能用实现接口的方式,而不能继承接口的适配器了。代码如下:
public class HelloWorld implements MouseListener...{ // or extends MouseAdapter
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(500, 375);
shell.setText("SWT Application");
shell.open();
Text HelloWorldText = new Text(shell, SWT.BORDER);
HelloWorldText.addMouseListener(new HelloWorld());
HelloWorldText.setText("HelloWorld");
HelloWorldText.setBounds(52, 68, 349, 29);
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
public void mouseDoubleClick(MouseEvent e) ...{
MessageDialog.openInformation(null,"","Hello ... ai wo de re !!");
}
//if extends MouseAdapter , delete the follow methods
public void mouseDown(MouseEvent e) ...{
}
public void mouseUp(MouseEvent e) ...{
}
}
SWT/JFace 中常用的事件
除了,上面用到的addMouseListener, Eclipse 还有一些常用的监听器,它们在各组件里的使用方法相同(如果该组件支持此种事件),简单介绍如下:
· addSelectionListener: 这个监听最常用。
widgetSelected 方法:当组件被选择(单击鼠标或按回车键)时触发此方法的事件处理程序。
widgetDefaultSelected 方法: 用于某些很少触发选择事件的组件,例如:文本框回车事件,列表框双击事件等。
· addKeyListener:
keyPressed 方法:当前焦点停留在组件时,按下键盘任意键时触发,但对于某些组件(如:button),按回车键无法执行此方法。
keyReleased方法: 按键弹起时触发。
· addFocusListener
focusGained方法: 得到焦点时触发。
focusLost方法: 失去焦点时触发。
eclipse学习笔记!(4) ----- SWT Designer 下 SWT常用组件收藏
· 一个button类的实例
基本的步骤和之前的是一样的,一个SWT的项目,然后在页面设置面板里添加button。双击button(直接在source里面添加了监听器的代码)。下面是代码:
public class ButtonTest ...{
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(500, 375);
shell.setText("SWT Application");
shell.open();
final Button okButton = new Button(shell, SWT.NONE);
//因为是比较简单的例子,只在这一个地方用这个的原因,所以用匿名方式
okButton.addMouseListener(new MouseAdapter() ...{
public void mouseUp(MouseEvent e) ...{
MessageDialog.openInformation(null,"","you click the "+ okButton.getText() +"button");
}
});
okButton.setText("OK.");
okButton.setBounds(97, 196, 244, 54);
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
程序说明: Button类的构造方法是new Button(Composite parent,int style),它有2个参数:
1. 第一个参数是指Button创建在哪个容器上,Composite是最常用的容器,而shell是Composite的子类,所以此参数也能接受shell和任何继承Composite的类。
2. 第二个参数用来指定button应用那种(或几种)式样,SWT.NONE是保持Button组件的默认式样。式样其实是一个常量,如SWT.NONE的值是0。等等....
3. 让button应用多是式样... 要生成一个文字靠左的,深陷型的复选框,只要用 “ | ” 将各个样式连起来即可,如下所示:new Button(shell,SWT.LEFT|SWT.BORDER|SWT.CHECK)。
· 组件的常用方法
SWT/JFace中的每一个组件之间都有很多同名的方法,很幸运这些方法在各个组件里的作用和用法都是相同或相似的,常用方法简述如下:
okButton.setImage(SWTResourceManager.getImage(ButtonTest.class, "275.jpg"));
okButton.setBackground(SWTResourceManager.getColor(158, 224, 167));
okButton.setText("OK.");
okButton.setBounds(81, 183, 244, 54);
等很多的方法,到现在的SWT编辑器下面这些常用的方法都可以在页面设置项里找到,所以很方便。
· 一个文本框(text类)的实例
本实例中创建一个文本框,它有如下功能:
1. 只能输入数字。
2. 至少输入一个值。
3. 长度不能多于10个字符。 (实例代码如下:)
public class ButtonTest ...{
private static Text text;
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(500, 375);
shell.setText("SWT Application");
shell.open();
final Button okButton = new Button(shell, SWT.NONE);
okButton.setImage(SWTResourceManager.getImage(ButtonTest.class, "275.jpg"));
okButton.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
String str = text.getText();
if (str == null || str.equals("")) ...{
MessageDialog.openInformation(shell, "", "please enter a number");
} else ...{
MessageDialog.openInformation(shell, "", "your enter the number is true");
}
}
});
okButton.setText("OK.");
okButton.setBounds(81, 183, 244, 54);
text = new Text(shell, SWT.BORDER);
text.setTextLimit(10); //最都只能输入10个字符
text.setBounds(70, 85, 228, 46);
text.addVerifyListener(new VerifyListener()...{//检查监听器,每输入一个字符都回触发
public void verifyText(VerifyEvent e) ...{
//检查输入字符(e.text)是否在0123456789这个字符串中,不在indexOf会返回-1
boolean b = "0123456789".indexOf(e.text) >= 0 ;
e.doit = b; //doit属性如果为true,则字符允许输入,反之不允许
}
});
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
注意到这次MessageDialog的第一个参数用了shell做参数,而不是以前的null。两者的区别在于:用shell时,则弹出提示窗口时,windows任务栏不会新增一个任务项;用null时,则多出一个任务项。
常用方法:
1. setEchoChar(char echo)
说明:将输入到文本框的字符表示成echo字符.
例子:text.setEchoChar('*');相当于SWT.PASSWORD式样。
2. setTabs(int tabs)
说明:按Tab键时前进多少个空格的长度,默认值为8.只有当text的样式为SWT.MULTI,SWT.V_SCROLL,SWT.H_SCROLL时,此设置才会有效。
例子:text.setTabs(4) 按键时前进4个空格长度
3. setTopIndex(int index)
说明:转到文本框的第index行,0为第一行,此命令可以在文本框中进行快速行定位。
例子:text.setTopIndex(0); 将当前行定位到首行上。
4. setTextLimit(int limit)
说明:设置最大入力数。
例子:text.setTextLimit(10); 文本框最多只能输入10个字符。
· 一个下拉框(combo类)的实例
public class ComboTest ...{
private static Combo combo;
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(500, 375);
shell.setText("SWT Application");
shell.open();
combo = new Combo(shell, SWT.READ_ONLY);//定义一个只读的下拉框
combo.setBounds(84, 67, 308, 59);
final Button button = new Button(shell, SWT.NONE);
button.setText("input key");
button.setBounds(54, 220, 135, 52);
button.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
combo.removeAll(); //先清空combo
for(int i=1;i<10;i++)
combo.add(i+"");//在combo中显示 1 到 9
combo.select(0); //设置 当前项是第一项
}
});
final Button button_1 = new Button(shell, SWT.NONE);
button_1.setText("get key");
button_1.setBounds(276, 220, 124, 52);
button_1.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
MessageDialog.openInformation(shell, null, combo.getText());
}
});
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
程序说明:
在这个例子中最关键的是设置值部分的代码,它是用add添加的,还有一种combo类设置值的方法,是将所有的值存到一个字符串数组,然后将这个数组作为参数,批量加入到combo中,语句如下:
combo.setItems(new String[]{"1","2","3"});
让combo的各项和对象一一对应
combo中的项只能是字符串,但是在实际应用中有很多这样的需要:将combo中的各项和一些对象一一对应起来。这些对象可以是任何类,这时就可以根据选择各项来得到相应的对象。
要实现这样的功能,使用setData方法就可以了。基于上面的例子,只需要修改设值和取值的事件代码。代码如下:
... ...
final Button button = new Button(shell, SWT.NONE);
button.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
combo.removeAll();
for(int i=1;i<10;i++)...{
combo.add(i+"no used");//这时的这行代码的作用就仅仅是在页面上显示的标签
combo.setData(""+(i-1), new Integer(i)); //关键代码,具体说明看下面的【代码说明】
}
combo.select(0);
}
});
... ...
final Button button_1 = new Button(shell, SWT.NONE);
button_1.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
String key = "" + combo.getSelectionIndex(); //取得key
Integer selectObject = (Integer)combo.getData(key);//通过key 取得object
//下面是显示结果
MessageDialog.openInformation(shell, null, "select the Integer is "+ selectObject.toString());
}
});
... ...
程序说明:
setData方法的格式是:setData(key,Object),它将对象(Object)对应一个键值(key),然后附着在combo上,键值可以是任意字符串,上例中之所以用""+(i-1),是因为它的值正好和combo的SelectionIndex值(当前项的序号)相同,这样在取值时就方便了。另外SelectionIndex的起始值是0,所以要 i -1 ( i 循环起始值是1)。
combo中的样式 SWT.SIMPLE(无须单击下拉框,列表一直显示)
常用方法除了上面用到的,还有combo.deselectAll();就是让当前的选择项为空,就是不选择任何项。
select( int index); 将index+1项设置为当前选择项。 combo.select(0);使首项为选择项。
setText(String string) 此方法和上面的一样也是设置当前选择项的。区别是上面是通过Index来选择的,这个是通过combo里面的String的内容来选择的,例如: combo.setText("中国"); 就是把中国的那项选择为当前选择的,另外setText没有选择的背景阴影,select则有。
· 列表框(List类)
list的用法和combo基本一致,combo的两个例子只要将Text定义部分改为list的定义语句,再稍微修改,即可成为list类的例子。
在list中设值的方法和combo是一样的,但取值有所不同,这时因为list可以选择多项,而combo只能选择一项,combo'的getText可以得到当前选择项的字符串,而list由于可以选择多项,所以就不行了。
list取值用getSelection()方法,它返回的是一个所有选项组成的String数组。
eclipse学习笔记!(5) ----- SWT Designer 下容器类收藏
在前面的例子中,所有的组件都是放在shell中的,但是Composite才是最常用的容器类。组件是构建在容器类中的,这样就可以通过容器对组件进行集体操作了,例如,容器在页面上移动,其他组件也会跟着移动;容器隐藏,其他组件页会隐藏,容器销毁,其他组件也会销毁。
面板(Composite类)
格式:Composite(Composite parent , int sytle )
用法:Composite composite = new Composite(shell,SWT.NONE);
说明:这里第一个参数还是用了shell类,因为shell类属于Composite的子类,所以shell也可以当作Composite类型来用。Composite的式样一般都是用SWT.NONE,这时Composite的界面是不显示出来的,只暗地里发挥容器的作用,当然也可以用SWT.BORDER式样让它形成凹陷效果。
常用方法:
composite.getLayout(); 得到布局管理器
composite.getLayoutData(); 得到本身的布局数据
composite.getParent(); 得到容纳composite的父容器
composite.getShell(); 得到容纳composite的shell
composite.layout(); 将composite的组件重新布局,相当于刷新功能
分组框(Group类)
Group是composite的子类,所以Group和composite基本一样,主要区别是Group显示有一个方框,且方框上可以显示一串文字说明。
选项卡(TabFolder 类和 TabItem 类)
TabItem 并非容器类,所以Group是不能建立在TabItem 中的,Group和TabItem 以及其他组件一样建立在TabFolder容器下。
每一个TabItem 只能用setControl方法来控制一个页面组件。这样我们把页面上的组件放到一个Group中,或composite中,在用TabItem 来控制一个Group的话,就相当于控制了一个页面了。
分割窗(SashForm类)
分割窗是一个很常用的组件,资源管理器左右两个容器就是用分割窗分割开来的,只需要将组件创建在分割窗容器上,它就会自动的按设计好的方式分割排列好,在使用上很简单。
带滚动条的面板(ScrolledComposite类)
有些界面的组件会多到一个窗口无法装下,这时ScrolledComposite类就派上用场了。不过,ScrolledComposite虽然是Composite的子类,但不要将组件直接建立在ScrolledComposite中,而应该将组件都建立在Composite上,然后在将composite建立在ScrolledComposite中,也就是说用一个composite来做中转。
eclipse学习笔记!(6) ----- SWT Designer 下布局管理器收藏
·
布局管理器简介
VB,Delphi程序不需要布局管理器,而java GUI 程序卻需要,是因為java开发程序的目标是要跨平台的,而每一个OS对屏幕的定义是不一样的。如果像 VB,Delphi那样使用绝对坐标定位界面组件,那么在windows下看着好好的界面,到了Linux,MacOS下,就变的一塌糊涂。除非你开发的java GUI只在Windows下运行,但即便如此,在不同的屏幕分辨率下,界面的形状也会大不一样!所以用了布局管理器的话,不论在说明OS,说明分辨率下,界面都不会变形。
SWT中主要的几种布局管理器如下所示:
FillLayout 充满式布局管理器,组件的大小会尽量充满整个容器。
RowLayout 行列式布局管理器,简单的排列组件。
GridLayout 网格式布局管理器,非常强大,可以胜任所有布局。
FormLayout 表格式布局管理器,通过创建组件各个边的距离来布局组件,和GridLayout一样强大。
StackLayout 堆栈式布局管理器,项书页一样只显示最前面的组件。
· 充满式(FillLayout 类)
FillLayout 是最简单的布局类,它把组件摆放在一排或一列,并强制组件大小一致。一般的组件的高度和最高组件相同,组件的宽度和最宽组件相同。另外,FillLayout 不能折行,不能设置边界距离和间距。
FillLayout 一般使用与任务栏,工具栏,Group中的一组复选框,或者容器中只有一个组件的时候。例如,如果一个shell内只有一个Group组件,那么将FillLayout用于Shell,则其内的Group将完全充满Shell.
FillLayout 默认情况下,是从左到右以此排列的,如果项上下来的话,只需要,将“new FillLayout()”改为“new FillLayout(SWT.VERTICAL)”,则可以上下来显示了。
· 行列式(RowLayout类)
RowLayout可以使组件折行显示,并可以设置边界距离和间距。另外,它可以对每个组件通过setLayoutData方法设置RowData对象,RowData用来设置组件的大小。
其中相应的代码 new RowLayout(); 的时候还可以对RowLayout进行设置(代码设置和页面desigin设置都可以),如:组件和容器上边缘距离,左边缘...组件之间间隔(spacing)等等。
使用rowLayout.wrap控制自动折行(默认为true),可以通过RowLayout的详细属性的设定来改变,也可以通过代码来实现,rowLayout.wrap = false;效果相同,页面上的组件会不折行的显示(后面的就看不到了,晕!)
使用SWT.VERTICAL式样,则变为垂直排列组件。同样可以通过RowLayout的详细属性的设定来改变。
使用RowLayout.pack控制组件大小(默认为true,大小可以控制)RowLayout.pack=false,组件大小相同。
使用RowLayout.justify控制空间伸展(默认为false)rowLayout.justify=true,让组件可以根据空间进行伸展。
使用RowData更改按钮的外观
当RowLayout.pack=false 的时候,进行其他它的设置的时候,只是改变按钮在容器中的布局,而对按钮的外观形状(如:大小)没有影响。
如果要改变按钮本身的外观,则要使用RowData类,RowData称为布局管理类,为RowLayout专用。GridLayout类也有专门的布局管理类GridData,GridData的目的也和RowData一样,即改变容器中组件的外观形状。
RowData最常用的格式是:new RowData(int width ,int height)。
例如:b1.setLayoutData(new RowData(30,50)); 是把b1組件设定大小!
· 网格式(GridLayout 类)
GridLayout类可能是最常用,功能最强大的标准布局类了,当然它也最复杂。GridLayout的布局方式是把容器里的组件摆放在一个个格子里,它有许多可设置项,并且和RowLayout一样也有专用的布局管理类GridData。GridData的使用颇为复杂,而GridLayout的强大之处也在于它可以通过GridData来设置每一个组件的外观形状!
使用GridLayout.numColumns设置列数,numColumns 是GridLayout 最重要的属性,通常它是要第一个设置的属性。GridLayout.numColumns=2,就把容器分成2列。
使用makeColumnsEqualWidth把组件等距离分开(默认为false),这时相当于把容器等距离分成几份(横向)。
GridLayout边距和间距的设置和RowLayout类似:
同样可以分别设置horizontalSpacing(列之间的间距) 和verticalSpacing (垂直间距) ,RowLayout 中的间距格局组件是水平 or 垂直排列来设置水平间距或垂直间距。
不同的是,左边距右边距统一成 marginWidth ,上边距下边距,统一成 marginHeigth.
使用GridData 来控制复杂布局,GridLayout 和 GridData 相结合可以变化出很多复杂的布局方式。 需要注意的是:一个GridData 对象只能用于一个组件,如果多个组件共用,会引起界面的紊乱。
1. horizontalSpan 是设置组件占用的列数。给出一个实例,代码如下:
public class Tabfolder1 ...{
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setLayout(new GridLayout(2,false)); //2列
shell.setMinimumSize(new Point(5, 26));
shell.setSize(500, 365);
shell.setText("SWT Application");
shell.open();
new Button(shell, SWT.NONE).setText("b1");
new Button(shell, SWT.NONE).setText("button2");
final Button button = new Button(shell, SWT.NONE);
GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
gridData.widthHint = 24;
button.setLayoutData(gridData);
button.setText("b3");
new Button(shell, SWT.NONE).setText("button4");
new Button(shell, SWT.NONE).setText("button5");
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
2.上面例子中b3按钮拥有2列布局空间,但是大小没有变,组件的占用空间和拥有的空间可以不同,如果要b3也占用2列空间,只需要将上面代码中的定义GridData的那句改为:GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);即可。GridData.HORIZONTAL_ALIGN_FILL是一个int常量,叫“水平对齐式充满”。
3.gridData.FILL_HORIZONTAL(水平抢占式充满),它会将水平方向所有的空间占为己有。
4.gridData.FILL_BOTH(双向抢占式),相当于水平和垂直抢占式合并的效果。
5.gridData.horizontalAlignment和gridData.verticalAlignment,这两个属性用来设置组件在格子里的对齐方式。它有4种对齐方式:BEGINNING(默认值)左对齐,CENTER,居中,END,右对齐,FILL,添满。
6.gridData.horizontalIndent 属性可以使组件向右移动指定长度(像素),此属性只有当horizontalAlignment设为BEGINNING(默认值)时有效。
7.gridData.grabExcessHorizontalSpace、gridData.grabExcessVerticalSpace(默认值false)
这两个属性主要是用在Text,List中,效果是:当组件所在的容器大小改变时,组件的占有空间也自动的增大或减小。例如:设置一个Text 组件为grabExcessHorizontalSpace= true,那么当用户调整窗口,导致容器宽度发生变化时,Text所在的列空间也会随着变化(组件的大小不会变化),但在同一行的其他组件会保持宽度不变。
8.gridData.widthHint、gridData.heightHint 属性可以改变组件的宽度和高度,但前提是不与GridLayout的其他设置相矛盾。
· 堆栈式(StackLayout类)
StackLayout 称作堆栈式布局,所谓堆栈式,就是像一副叠在一起的扑克牌,只显示最上面的那个扑克(面板),和awt/swing里面的cardLayout的感觉是一样的,下面是一个简单的例子:
public class Tabfolder1 ...{
private static Text text2;
private static Text text1;
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setLayout(new FillLayout());
shell.setMinimumSize(new Point(5, 26));
shell.setSize(500, 365);
shell.setText("SWT Application");
shell.open();
final Composite composite = new Composite(shell, SWT.NONE);
final StackLayout stackLayout = new StackLayout();
composite.setLayout(stackLayout);
text1 = new Text(composite, SWT.BORDER);
text1.setText("text1");
text2 = new Text(composite, SWT.BORDER);
text2.setText("text2");
final Composite composite_1 = new Composite(shell, SWT.NONE);
final GridLayout gridLayout = new GridLayout();
gridLayout.marginWidth = 80;
gridLayout.marginTop = 30;
gridLayout.numColumns = 2;
composite_1.setLayout(gridLayout);
final Button show1Button = new Button(composite_1, SWT.NONE);
show1Button.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
//关键代码就下面2行, 下面首先是让text1放在上面(top)出来
stackLayout.topControl = text1;
composite.layout(); //刷新,否则,看不到效果的
}
});
final GridData gd_show1Button = new GridData();
show1Button.setLayoutData(gd_show1Button);
show1Button.setText("show1");
final Button show2Button = new Button(composite_1, SWT.NONE);
show2Button.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
stackLayout.topControl = text2;
composite.layout();
}
});
final GridData gd_show2Button = new GridData();
show2Button.setLayoutData(gd_show2Button);
show2Button.setText("show2");
shell.layout();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
· 表格式(FormLayout 类)
FormLayout 是一种和GridLayout一样强大,而且还很灵活、精确的布局,这个布局是SWT2.0版新增的,通常GridLayout和FormLayout 是可以做到相同的效果的,但有时使用FormLayout 会更有效,不会像GridLayout因容器大小变化而导致布局错位。
使用marginWidth、marginHeight设置边距(左边距,上边距)。
使用FormData的构造函数
FormLayout 也有自己的布局管理类FormData,它的使用方法是:new FormData() 或 new FormData(int width, int height)
FormAttachment 是在FormData下的,更进一步地布局管理类,它的用法主要体现在它的不同构造函数上。
1. new FormAttachment(int numerator, int offset)
如下例,button1的顶边(formData.top)离shell容器的空白边距是shell容器总体空白长度的60%,偏移点数(points)为0,代码如下:
......
shell.setLayout(new FormLayout());
new Text(shell,SWT.BORDER).setText("text1");
Button button1 = new Button(shell,SWT.NONE);
button1.setText("button1");
FormData formData = new FormData();
formData.top = new FormAttachment(60,0); //button1的顶部应用FormAttachment设置
button1.setLayoutData(formData);
...
如果将new FormAttachment(60,0);改为new FormAttachment(60,10); 则button1先60%,再下降10个像素。
new FormAttachment(int numerator)相当于new FormAttachment(int numerator, int offset)当offset=0时。
new FormAttachment(int numerator, int offset)相当于new FormAttachment(int numerator,int denominator, int offset) 当denominator=100 时,其中denominator 是分母,例如FormAttachment(30,50,0); 和FormAttachment(60,10);效果是一样的。
2. new FormAttachment(Control control,int offset, int alignment)
参数1是一个Control类,一般在使用的时候传入一个组件(如文本框)来做参数。应用此FormAttachment的组件将依据参数1的control为基准来布局,offset为离control的偏移量(单位:像素),alignment为对齐方式,下面是例子:
shell.setLayout(new FormLayout());
Text text1 = new Text(shell,SWT.BORDER);
text1.setLayoutData(new FormData(100,50));
FormData formData = new FormData();
//以text1为基准偏移50个像素
FormAttachment formAttachment = new FormAttachment(text1,50);
formData.top = formAttachment;
formData.left = formAttachment;
//将button1应用FormData
Button button1 = new Button(shell,SWT.None);
button1.setText("button1");
button1.setLayoutData(formData);
上例最终显示结果就是,button1以 text1为基准,分别向右和向下偏移50个像素。
可以把“FormAttachment formAttachment = new FormAttachment(text1,50);”这句,替换一下,就可以得到其他的结果。当前这句new FormAttachment(text1,50);不带alignment 相当于FormAttachment(text1,50,SWT.DEFAULT); 。当alignment =SWT.CENTER的时候,button1和text1的中心重合,因此在显示结果上看不到button1了。alignment =SWT.LEFT,以text1 的左边界为基准偏移,alignment =SWT.RIGHT,为右基准。alignment =SWT.TOP,alignment =SWT.BOTTOM,以上下边界为基准。
eclipse学习笔记!(7) ----- SWT Designer 下其他SWT組件收藏
· 工具栏(ToolBar类、ToolItem类、ViewForm类)
ViewForm是一个容器,它是编辑器的基座,用来容纳工具栏和文本框。ToolBar是一个工具栏,同时也是一个容器,即容纳工具栏的一个个按钮(ToolItem)。
在写例子或做其他的时候,只要注意将ViewForm放入到shell上,然后将ToolBar放到ViewForm上,之后将ToolItem放在ToolBar上,页面的基本效果就出来了。下面写一段比较简单的代码:
final ViewForm viewForm = new ViewForm(shell, SWT.BORDER);
viewForm.setLayout(new FillLayout());
final ToolBar toolBar = new ToolBar(viewForm, SWT.NONE);
final Text thisIsTestText = new Text(viewForm, SWT.BORDER|SWT.V_SCROLL);
thisIsTestText.setText("this is test!");
viewForm.setContent(thisIsTestText);
viewForm.setTopLeft(toolBar);
final ToolItem newItemToolItem = new ToolItem(toolBar, SWT.PUSH);
newItemToolItem.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
String str = thisIsTestText.getText();
MessageDialog.openInformation(null,null,str);
}
});
newItemToolItem.setText("show");
final ToolItem newItemToolItem_1 = new ToolItem(toolBar, SWT.PUSH);
newItemToolItem_1.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
thisIsTestText.setText("");
}
});
newItemToolItem_1.setText("hide");
上面例子里面的Layout 是FillLayout 布局方式!
· 动态工具栏(CoolBar类、CoolItem类)
CoolBar组件是一个可以放置多个工具栏的容器,基于CoolBar做出的工具栏可以通过拖动操作改变摆放位置(office系列的工具栏类似的效果)。
要做CoolBar工具栏必须是要CoolBar,CoolItem,ToolBar,ToolItem 四个一起使用才可以。其中ToolBar是建立在CoolBar容器里的,且CoolItem并非是用来显示按钮的,而是用来帮助CoolBar控制 ToolBar的。这里的CoolBar,CoolItem,ToolBar和前面说过的TabFolder,TabItem,Group三者是一样的关系。实例代码如下:
public class Tabfolder1 ...{
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(500, 365);
shell.setText("SWT Application");
shell.setLayout(new FillLayout());
//同样需要用ViewForm来做底层的容器
final ViewForm viewForm = new ViewForm(shell, SWT.NONE);
viewForm.setLayout(new FillLayout());
//在ViewForm上放CoolBar和Text
CoolBar coolBar = new CoolBar(viewForm,SWT.NONE);
Text text = new Text(viewForm,SWT.BORDER|SWT.V_SCROLL);
//设置CoolBar和Text在ViewForm上的位置
viewForm.setContent(text);
viewForm.setTopLeft(coolBar);
/**//*
* 为CoolBar添加2个工具栏,分别在2个大括号里面,括号本身没有意思,可以去掉
*/
...{
final ToolBar toolBar = new ToolBar(coolBar, SWT.NONE);
//为子工具栏添加2个按钮
final ToolItem newItemToolItem = new ToolItem(toolBar, SWT.PUSH);
newItemToolItem.setText("GET");
newItemToolItem.setImage(new Image(display,"src/275.jpg"));
final ToolItem newItemToolItem_1 = new ToolItem(toolBar, SWT.PUSH);
newItemToolItem_1.setText("CLEAR");
newItemToolItem_1.setImage(new Image(display,"src/275.jpg"));
//创建一个CoolItem来控制此子工具栏
final CoolItem newItemCoolItem = new CoolItem(coolBar, SWT.NONE);
newItemCoolItem.setControl(toolBar);
//调整ToolBar为合适的尺寸,并用ToolBar的尺寸来调整CoolItem
toolBar.pack();
Point point = new Point(toolBar.getSize().x,toolBar.getSize().y);
newItemCoolItem.setSize(point);
//设定CoolItem的最小尺寸,如不设定,则按钮会呗其他子工具栏遮住
newItemCoolItem.setMinimumSize(point);
}
...{//同样的方式创建一个子工具栏2
final ToolBar toolBar = new ToolBar(coolBar, SWT.NONE);
final CoolItem newItemCoolItem = new CoolItem(coolBar, SWT.NONE);
newItemCoolItem.setControl(toolBar);
final ToolItem newItemToolItem = new ToolItem(toolBar, SWT.PUSH);
newItemToolItem.setImage(new Image(display,"src/275.jpg"));
toolBar.pack();
Point point = new Point(toolBar.getSize().x,toolBar.getSize().y);
newItemCoolItem.setSize(point);
newItemCoolItem.setMinimumSize(point);
}
shell.layout();
/**//*
* 下面监听coolBar中子工具栏的改变,如有改变则重排viewForm中组件的位置。不加,则页面会出现重叠什么的
* 若此监听写在shell.layout()的前面,则窗口打开时,此事件就会触发一次,完全没有必要。为优化代码,所以...
*/
coolBar.addControlListener(new ControlAdapter()...{
public void controlResized(ControlEvent e)...{
viewForm.layout();
}
});
shell.open();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
· 菜单(Menu类,MenuItem类)
这个就不加代码了,比较的乱,看不清楚,要想比较清楚的了解,就必须自己动手了。个人感觉design比手写的要方便的多,比较快点(可能会有些冗余代码)。
一般创建Menu对象的第一个参数是shell,
创建MenuItem对象的第一个参数是MenuItem所在的Menu对象。
如果Menu是某个MenuItem的子菜单,则还需要加一个设置:MenuItem.setMenu(Menu);
Menu的式样罗列如下:
SWT.BAR ,用于主菜单
SWT.DROP_DOWN ,用于子菜单
SWT.POP_UP ,用于右键菜单(Windows桌面效果)
MenuItem的式样罗列如下:
SWT.CHECK ,选择后前面会加一个小勾
SWT.CASCADE ,有子菜单的
SWT.PUSH ,普通型
SWT.RADIO ,选择后,前面会显示一个圆点
SWT.SEPARATOR ,分隔符(显示一个横线,把几个选项隔开)
· 滑动条(slider)、刻度条(scale)、进度条(progressBar)
1. 滑动条(slider类)
下面代码显示结果:窗口里有2个组件,右边是一个滑动条,左边是一个用来显示滑动条当前值的文本框。
......
shell.setLayout(new RowLayout());
final Text text = new Text(shell, SWT.BORDER);
//创建一个滑动条,默认是水平型,用样式SWT.VERTICAL 可变成垂直型
final Slider slider = new Slider(shell, SWT.NONE);
slider.setMinimum(0); //最小值
slider.setMaximum(100);//最大值
slider.setIncrement(5);//滚动间隔值
slider.setPageIncrement(10);//翻页间隔值
slider.setSelection(25);//初始值
slider.addSelectionListener(new SelectionAdapter()...{
public void widgetSelected(SelectionEvent e)...{
text.setText("" + slider.getSelection());
}
});
......
2. 刻度条(scale类)---像小尺的样式
刻度条和滑动条在使用方法上是一样的。将上面代码中创建滑动条的语句修改如下,即可:
//final Slider slider = new Slider(shell, SWT.NONE);
final Scale scale= new Scale(shell, SWT.NONE);
3. 进度条(progressBar类)testCase的那种条条
进度条的使用方法和上面的2个类似,主要也是3种方法,setMinimum,setMaximum,分别是最小值和最大值,setSelection方法控制进度条当前的位置。具体代码如下:
shell.setLayout(new RowLayout());
final ProgressBar progressBar = new ProgressBar(shell, SWT.SMOOTH);
progressBar.setMinimum(0);
progressBar.setMaximum(100);
final Button button = new Button(shell, SWT.BORDER);
button.setText("GO");
button.addSelectionListener(new SelectionAdapter()...{
public void widgetSelected(SelectionEvent e)...{
for(int i=1; i<11 ; i++)...{
try...{
Thread.sleep(1000);//间隔1秒
}catch(Throwable e2)...{}
progressBar.setSelection(i*10);
}
}
});
程序说明:
上面程序演示了进度条的使用,但有一个大毛病,就是当开始执行处理过程时,页面就很难在响应其他的操作了,解决这个问题就需要用线程了。
另外JFace包里,有一种dialog组件“ProgressMonitorDialog”,它也有表示任务执行进度的功能。
· 画布(canvas类)
Canvas用于显示图像,既可以在Canvas上画图,也可以直接将图片显示于其中,通过下面的代码来演示Canvas使用的3个主要方面:设置图像、更换图像、清除图像。代码如下:
public class Tabfolder1 ...{
static Image image;
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(502, 360);
shell.setText("SWT Application");
shell.setLayout(new RowLayout());
final Canvas canvas = new Canvas(shell,SWT.BORDER);
canvas.addPaintListener(new PaintListener()...{//监听canvas的重绘事件
public void paintControl(final PaintEvent event) ...{//将其图像显示在canvas上
if(image != null)...{
event.gc.drawImage(image, 10, 10);//10,10是显示图像的左上角坐标
}
}
});
Button button1 = new Button(shell,SWT.NONE);
button1.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
image = new Image(display,"src/275.jpg");
canvas.redraw();
}
});
button1.setText("photo1");
Button button2 = new Button(shell,SWT.NONE);
button2.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
image = new Image(display,"src/pre.gif");
canvas.redraw();
}
});
button2.setText("photo2");
Button clearButton = new Button(shell,SWT.NONE);
clearButton.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
if(image != null)...{
image.dispose();
image = null;
canvas.redraw();
}
}
});
clearButton.setText("cleanPhoto");
shell.layout();
shell.open();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
· 表格(Table类)
实际项目中,多是有关DB开发的,一般不会用Table,而用JFace中基于Table扩展的TableViewer来作为表格组件。所以不多说了,随便看看下面代码实现下面的各功能:
public class Tabfolder1 ...{
static Image image;
public static void main(String[] args) ...{
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(502, 360);
shell.setText("SWT Application");
shell.setLayout(new FillLayout());
final Table table = new Table(shell,SWT.MULTI|SWT.FULL_SELECTION);
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableColumn col1 = new TableColumn(table,SWT.NONE);
col1.setText("ID");
col1.setWidth(80);
TableColumn col2 = new TableColumn(table,SWT.NONE);
col2.setText("name");
col2.setWidth(80);
Composite composite = new Composite(shell,SWT.NONE);
composite.setLayout(new RowLayout());
Button addButton = new Button(composite,SWT.NONE);
addButton.setText("add");
addButton.addSelectionListener(new SelectionAdapter() ...{
int i= 1;
public void widgetSelected(SelectionEvent e) ...{
TableItem item = new TableItem(table,0);
item.setText(new String[]...{""+i,"yjy"+i});
i++;
}
});
Button removeButton = new Button(composite,SWT.NONE);
removeButton.setText("remove");
removeButton.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
int[] x = table.getSelectionIndices();
table.remove(x);
}
});
table.addMouseListener(new MouseListener()...{
public void mouseDoubleClick(MouseEvent e) ...{
int x = table.getSelectionIndex();
TableItem item = table.getItem(x);
String str = "li one =" +item.getText(0) + " li two = " + item.getText(1);
MessageDialog.openInformation(null,null,str);
}
public void mouseDown(MouseEvent e) ...{ }
public void mouseUp(MouseEvent e) ...{ }
});
shell.layout();
shell.open();
while (!shell.isDisposed()) ...{
if (!display.readAndDispatch())
display.sleep();
}
}
}
· 数(tree类)
和Table一样,JFace里也有基于Tree扩展的TreeViewer,实际用到数据库的项目都用它。还是简单介绍下:
shell.setLayout(new FillLayout());
final Tree tree = new Tree(shell,SWT.SINGLE);
TreeItem chinaItem = new TreeItem(tree,SWT.NONE);
chinaItem.setText("china");
new TreeItem(chinaItem,SWT.NULL).setText("beijing");
new TreeItem(chinaItem,SWT.NULL).setText("taiwan");
new TreeItem(chinaItem,SWT.NULL).setText("shanghai");
new TreeItem(tree,SWT.NONE).setText("USA");
tree.addSelectionListener(new SelectionAdapter()...{//单击tree的节点时,节点的值显示在窗口标题栏中
public void widgetSelected(SelectionEvent e)...{
//Tree也可以支持多选,所以getSelection返回的是数组,本例没有设置多选
TreeItem[] item = tree.getSelection();
shell.setText(item[0].getText());
}
});
eclipse学习笔记!(8) ----- SWT Designer 下图像设置收藏
· 图像(Image类)
开发项目中少不了用到图像,在SWT中图像是Image类,它有多种构造函数,下面主要介绍new Image(Device device,String filename),来介绍,其中Device称为设备,它包含Display(显示)和Print(打印),两种设备。
前面的很多例子里已经包含了图像的显示了,都是用的Display 设备。
Image是比较重量级的对象,占用内存很大,一般来说,当应用程序退出时,会释放掉Image所占用的资源。但某些OS由于特殊原因,Image仍有可能继续存在于系统内存中。综上所述,为了提高Image对象的使用率,在Eclipse中Image是可以被各组件共享的。当窗口关闭时,Image不会自动清除掉,而是继续保留在系统中,以便被其他窗口组件使用,因此如果肯定程序中不会在使用某个Image对象,就应该用Image的dispose()方法,立即释放掉Image。
类似情况的还有,font(字体),color(颜色)等.
· 图像描述符(ImageDescriptor类)
由于Image存在的一些问题,Jface包提供了一个轻量级的ImageDescriptor类,ImageDescriptor并不存储图像本身,而是在程序需要时,才会创建图像,并且有些界面组件也只接受ImageDescriptor做参数来设置图像。
ImageDescriptor是一个抽象类(abstract),所以它不能用new的方式来创建。下面介绍ImageDescriptor的两种静态方法createFromFile、createFromURL来生成图像描述符的方法。
1.CreateFromFile方法
ImageDescriptor imageDesc = ImageDescriptor. CreateFromFile(abc.class,”src/275.jpg”)
此句指当要创建图像时,会通过abc.class类所在目录下的src子目录来加载275.jpg,此时imageDesc只是包含了指向275.jpg的信息。还没有真正加载图片,abc.class这个参数可以是这个项目中的其他类,甚至是写这个语句的类也可以。(注意实际运用时候275.jsp放在abc.java类所在目录下。)
2. createFromURL方法
URL url = new URL(“file:\\E:\\src\\275.jpg”);
ImageDescriptor imageDesc = ImageDescriptor. createFromURL (url)
3. 利用Eclipse自带的图像
如果开发插件,由于插件是基于Eclipse环境运行的,所以还可以用Eclipse自带图像。
ImageDescriptor imageDesc = WorkbenchImages.getImageDescriptor(
iWorkbenchGraphicConstants.IMG_ETOOL_HOME_NAV)
4. ImageDescriptor总结
ImageDescriptor比image有个好处,如果前者所指图像路径错误,则会自动用一个红色方块图像代替,而不会像后者那样弹出错误提示框。另外由ImageDescriptor也可得到image,方法是:Image image = imageDesc.createImage();
· 图像注册表(ImageRegistry类)
JFace提供了一个高速提供了一个能高速缓冲图像和图像描述符的图像注册表。它的设计思路是:先创建指向图像的图像描述符,然后将图像描述符加上一个键值添加到图像注册表中,这个键值和图像描述符一一对应的。当希望获得图像时,就可以用键值从注册表中取得。
下面是一个图像注册表加值,取值,移除的方法。代码如下:
/**//*
* 创建一个图像注册表,因为程序需要共享图像注册表ImageRegistry,所以在实际项目中
* 最好将ImageRegistry设置成静态变量(类变量)以使它可以被全局访问
*/
ImageRegistry imageRegistry = new ImageRegistry();
//创建一个图像描述符对象
URL url = new URL("file:src/275.jpg");
ImageDescriptor imageDesc = ImageDescriptor.createFromURL(url);
//将图像描述符添加到图像注册表,键值为“refresh”
imageRegistry.put("refresh", imageDesc);
//将图像从图像注册表取出
Image image = imageRegistry.get("refresh");
//从图像注册表取出图像描述符
ImageDescriptor imageDesc2 = imageRegistry.getDescriptor("refresh");
/**//*
* 将图像从注册表里移除,如果有组件正在使用这个图像,图像依然会被释放掉,组件上就不会显示此图像.
* 另外,如果注册表里没有这个键值“refresh”也不会显示错误或异常.
*/
imageRegistry.remove("refresh");
eclipse学习笔记!(9) ----- SWT Designer 下 SWT的线程(*很不错应用*)收藏
· 简介
多数情况下,GUI界面编程不需要考虑线程问题,SWT已经帮助我们隐藏了底层的线程调用。但一些特殊应用,却不得不涉及SWT线程编程。
在实际项目开发中,一种常见的应用是:单击前台界面的执行后,在后台要做一些任务处理,任务执行情况要反映在界面上,而且还不能影响前台界面的其他操作
这种应用的实现思路如下:
前台界面和后台程序分开2个类。
为后台程序另开一个线程,这样就可以让前台操作不受后台影响了。
前台界面提供一些可操作的组件的方法,后台处理程序调用这些方法,将执行情况的字符串写到前台界面组件中。
这种思路必须解决一个关键问题:界面本身有一个默认线程,后台程序又是另外一个线程。那么该如何在一个线程中访问另外一个线程呢?
(1)为后台新开一个线程,这要用到JDK中线程的知识,代码如下:
new Thread()...{ // 新开一个线程,这是匿名内部类的写法
public void run()...{
//开始后台任务
}
}.start();//start表示立即开始线程
(2)从后台处理线程中访问前台界面组件,关键在于使用display对象,因为display主要负责管理时间循环和控制UI线程和其他线程之间的通信。display的具体使用方法如下:
Display.getDefault().asyncExec(new Runnable()...{//又是一个匿名内部类写法
public void run()...{
//对前台界面的操作
}
});
在这里的display对象很关键,因此顺便给出得到display对象的2种方法:
Display.getDefault(),得到一个默认的display对象,应用程序一般只需要一个display对象。
Display.getCurrent(),得到当前运行线程所在的display对象,如果生成2个以上的display对象,则可用此方法。
· 一个SWT线程的实例
本实例分2个类:一个前台界面类,一个后台处理类。实例功能说明如下:
单击“GO”按钮时,开始后台处理。
单击“STOP”按钮,立即中断后台处理。
后台处理的任务数根据前台界面文本框的值来决定。
进度条将实时反映后台处理的进度。
底部的文本框将以文字形式反映后台处理的进度情况。
实例具体代码如下:
1. 前台界面类
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class TaskGUI ...{
private Display display = Display.getDefault();
private Shell shell = new Shell();
private Task task = new Task(this);//Task是后台处理类,需要传入一个TaskGUI类型参数
//将界面组件设为类的实例变量
private Text taskCountText;//可输入任务数的文本框
private Button startButton;//开始
private Button stopButton;//结束
private ProgressBar progressBar;//显示的任务条
private Text consoleText;//显示当前后台进度的信息条
//主函数
public static void main(String[] args)...{
try...{
TaskGUI window = new TaskGUI();
window.open();
}catch(Exception e)...{
e.printStackTrace();
}
}
//前台页面的执行方法,显示出可操作的前台界面、
public void open() ...{
shell.setSize(300,300);
shell.setLayout(new GridLayout());
Group group = new Group(shell,SWT.NONE);
group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
group.setLayout(new GridLayout(4,false));
new Label(group,SWT.NONE).setText("taskCount:");
taskCountText = new Text(group,SWT.BORDER);
taskCountText.setText("10");
taskCountText.setLayoutData(new GridData(100,-1));
taskCountText.addVerifyListener(new VerifyListener()...{
public void verifyText(VerifyEvent e) ...{ //only input NO.
e.doit = "0123456789".indexOf(e.text)>=0;
}
});
startButton = new Button(group,SWT.PUSH);
startButton.setText("GO");
startButton.addSelectionListener(new SelectionAdapter() ...{//点击开始按钮
public void widgetSelected(SelectionEvent e) ...{
setButtonState(false);//点击后,2个Button发生变化
//得到任务数,多线程使用的变量要求类型为final
String str = taskCountText.getText();
final int taskCount = new Integer(str).intValue();
//设置进度条的格数
progressBar.setMaximum(taskCount-1);
consoleText.insert("back Thread run start... ... ");
//为后台新开一个线程,运行,当run方法结束(即后台的start()结束),线程自动销毁
new Thread()...{
public void run()...{
task.start(taskCount);
}
}.start();
consoleText.insert("back Thread run end... ... ");
}
});
stopButton = new Button(group,SWT.PUSH);
stopButton.setText("STOP");
stopButton.setEnabled(false);
stopButton.addSelectionListener(new SelectionAdapter() ...{
public void widgetSelected(SelectionEvent e) ...{
task.stop();//后台执行stop方法,实际是要后台任务停止
}
});
progressBar = new ProgressBar(shell,SWT.NONE);
progressBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
//下面2个是设置,文本框的显示格式,第2行的如果不加则会看不到全部信息了
consoleText = new Text(shell,SWT.MULTI|SWT.BORDER|SWT.V_SCROLL);
consoleText.setLayoutData(new GridData(GridData.FILL_BOTH));
shell.layout();
shell.open();
while(!shell.isDisposed())...{
if(!display.readAndDispatch())...{
display.sleep();
}
}
}
public void setButtonState(boolean bFlag)...{//设置页面的2个按钮状态
startButton.setEnabled(bFlag);
stopButton.setEnabled(!bFlag);
}
//为后台取得页面组件写的几个GET方法
public Shell getShell()...{
return shell;
}
public Text getConsoleText()...{
return consoleText;
}
public ProgressBar getProgressBar()...{
return progressBar;
}
}
2. 后台任务类
import org.eclipse.swt.widgets.Display;
public class Task ...{
private TaskGUI gui;//通过构造器得到前台界面对象
private boolean stopFlag;//是否停止的标志
//构造器 取得前台界面对象
public Task(TaskGUI taskGUI)...{
this.gui = taskGUI;
}
public void stop()...{
stopFlag = true;
}
//就是前台run方法的执行内容,这个方法结束,则前台new的那个线程销毁
public void start(int taskCount)...{
stopFlag = false;//将执行状态初始化执行
insertConsoleText("backGO start ... ... ");
for(int i=0;i<taskCount;i++)...{
if(stopFlag)...{//点击stop按钮则这个属性为true,跳出循环
break;
}
try...{//每隔1秒一次循环
Thread.sleep(1000);
}catch(InterruptedException e)...{
e.printStackTrace();
}
//页面上的信息累加
insertConsoleText("task"+(i+1)+"the end ");
//移动进度条的进度
moveProgressBar(i);
}
insertConsoleText("the thread end of the task!! ");
setTaskGUIButtonState(true);
}
//修改页面按钮的状态
private void setTaskGUIButtonState(final boolean bFlag)...{
Display.getDefault().asyncExec(new Runnable()...{
public void run()...{
gui.setButtonState(bFlag);
}
});
}
private void moveProgressBar(final int progress)...{
Display.getDefault().asyncExec(new Runnable()...{
public void run()...{
gui.getProgressBar().setSelection(progress);
}
});
}
private void insertConsoleText(final String str)...{
Display.getDefault().asyncExec(new Runnable()...{
public void run()...{
gui.getConsoleText().insert(str);
}
});
}
}
程序说明:
从上面代码的执行结果可以看到,前台new 了一个新的 thread 后,后面的那句文本依然可以输出,可以明确的说明,new了一个线程后,前台,后台线程是互补干扰的独自运行。当start方法结束时,后台的线程就自动销毁。