SWT 小总结下,做了个很简单的小玩意,总结一下,顺便把里面觉得比较有代表性的地方都记下来。
包结构设计和分层
这次几乎没有什么完整的分层,至于之前说到的Java swing 的MVC ,我还是用不上。如图。
首先引进的库有Java 运行时库 (JRE 系统库)和SWT 开发用库 (在“引用的库”里边),如果是直接从外边拉进或者复制粘贴到project 里面的,记得要把库路径加入project 的classpath 里面。
包的设计分部是:
1. app :应用程序文件,里面只有一个文件,文件里面只有一个main 方法,直接调用主程序窗口。其实可以直接在窗口类启动,但是那样不符合应用和界面分开的原则。
2. com.swtdesigner :这次用了MyEclipse 的SWTdesigner 插件,但是几乎没有用到里面的自动生成,都是自己手打的代码,为什么不用,我后面会说。而这个包是自动生成的,我打开里面的Java 文件,估计可能是SWTdesigner 自定义的一些方法。不讨论。
3. model :用来放置处理成模型的文件,这次主要包括一个用来存储数据表的JavaBean ,即Table.java 和处理输出的Dispose.java 两个。
4. shell :是窗口类,窗口都继承自UI 包里改写统一的Shellmodel.java 。其中运行逻辑也在窗口类中,没有分离开。
5. UI :如上所说,是完全继承空间类的界面类,用于统一一些东西。
另外还有源文件夹resources 。源文件夹和文件夹的区别就是,源文件夹是添加进classpath (类路径,启动或者运行的时候,从该文件里面找到对应的文件,在eclipse/MyEclipse 中右击项目,属性/properties ,构建路径/Java buildpath ,可以对项目classpath 进行编辑),而普通文件夹就是个文件夹,没有添加进classpath 。resources 是用来放一些图片或者声音的,图片和声音属于这项目的一部分,为了可移植性,应该把资源文件(图片和声音等)放在类路径里面,而不是用绝对路径(比如在桌面:C:\Users\Default\Desktop ),除非你保证每一台运行的机器上面的绝对路径里都有你要的资源文件(不太现实吧…)。
UI 包
UI 包的作用是统一控件模型,比方说,你所有的窗口都有同样的图标,而且都要求是固定尺寸,没有最大化的功能,总在最上,模式窗口等等,这些你完全可以用一个UImodel 文件来继承Shell ,然后在构造方法里面设定。按照上面要求,UI 类如下:
public class ShellModel extends Shell { public ShellModel(Shell shell) { super(shell, SWT.RESIZE | SWT.MIN | SWT.ON_TOP | SWT.APPLICATION_MODAL); /* 用父类的构造方法,样式分别代表:固定尺寸,存在最小化和关闭按钮,总在最上,模式窗口 */ setImage(SWTResourceManager.getImage(ShellModel.class, "/images/espada.png")); /* 设置统一图标,getImage是一个静态方法,参数是图片文件,如果已经加进classpath,直接调用classpath里面设置好的文件路径就行了 */ } @Override protected void checkSubclass() { } }
如注释所说。需要提出的一点是:如果要使一个SWT 控件可以继承,就必须实现 checkSubclass () 方法,并且有一个空的实现 ,如上所示。否则编译时会出现 Subclassing not allowed 的错误提示。
写UI 类主要是把窗口初始化的一些统一而重复的工作都统一起来,方便以后如果要修改的话也灵活容易。
用SWTdesigner 和手写的区别
不用插件让它自动生成代码的原因就是,跟我想设计的代码结构太不同了。以下是我的代码结构。
public class MainShell extends Shell { //控件的定义 Group operationGroup = new Group(this, SWT.NONE); ……………………//省略一系列控件的定义 //构造方法,在定义声明MainShell的时候调用构造函数,生成所有的界面 public MainShell(Display display) {} // 设置监听器方法,抽离出监听器方便统一修改 Listener listener = new Listener() {} SelectionListener selectionListener = new SelectionAdapter() {} ……………………//省略一系列监听器方法的定义 // 以下是自定义的工具方法 protected void setList() {}// 设置进去左边的list ……………………//省略一系列自定义工具方法的定义 @Override protected void checkSubclass() {} }
让SWTdesigner 自动生成的代码,把各种控件的定义和实例化都写在构造方法里面,个人感觉把对象模型都混了,而且监听器也是采用匿名内部类。
我把各种要添加的控件都写成属性,控件的样式则在构造方法中设定。这样就容易把监听器分离出来。
控件描述
如下,runButton 是之前定义的一个按钮。
// 按钮 runButton.setText("执行"); runButton.setBounds(413, 209, 42, 30); runButton.addSelectionListener(selectionListener);
最后增加监听器不是用内部类,而是调用在本文件里定义的selectionListener() 。selectionListener() 如下节。
监听器结构
selectionListener() 监听器定义如下:
SelectionListener selectionListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { Widget widget = e.widget; if (widget == ***) ………………………… } else if (widget == ***)//其他控件监听器方法 ………………………… } else if (widget == runButton) …………………………//runButton的监听器方法 } };
这样子在类里面定义一个监听器方法。在监听器里面用 Widget widget = e . widget ; 得到触发事件的控件,然后根据控件不同写各种监听实现。
SelectionAdapter () 和 SelectionListener () 不同的地方在于, SelectionAdapter () 是适配器,只要实现原本 SelectionListener () 里面你想实现的方法就行了,而如果用 SelectionListener () 则必须实现该接口定义的所有方法。其他监听器接口都有对应的适配器类。
使窗口在屏幕正中央的方法
如下,在构造方法中写。
Rectangle bounds = display.getPrimaryMonitor().getBounds(); Rectangle rect = getBounds(); int x = bounds.x + (bounds.width - rect.width) / 2; int y = bounds.y + (bounds.height - rect.height) / 2; setLocation(x, y);
很简单,不解释……也可以用awt 的方法写,但是不建议,不想让程序杂七杂八的,用了SWT 就尽量用SWT 提供的类库和方法。
窗口打开另一个窗口
有个可能会有很多人遇到不知道怎么处理的问题。如果想实现按下当前窗体(窗口1 )的一个按钮就弹出一个另一个窗口(窗口2 ),而窗口2 结束以后把结果反馈到窗口1 上面(就是在窗口2 的操作会影响窗口1 ),实际操作发现两个窗口是异步的,也就是说,单单生成一个窗口,然后调用open() 方法是不行的,因为这样只是打开了窗口2 ,打开完以后窗口1 会继续执行它接下来的语句,窗口2 的反馈信息显示不了到窗口1 上面。
是这样子解决的。
Shell shell = new Shell(runButton.getDisplay()); shell.open(); while (!shell.isDisposed()) if (!shell.getDisplay().readAndDispatch()) shell.getDisplay().sleep();
前两行是实例化窗口并open() ,后面表示,当该shell 已经配置未被处理掉(第3 行),如果该shell 的display 当前没有执行什么程序,就让它休眠(不占用CPU 资源)。
实现窗口内容的复制
比方说实现对一个text 控件里面的文本复制到剪贴板,没有这样一个方法。当然你可以用新建一个剪贴板对象的方法,但是比较麻烦,其实可以利用几个组合来达到。如下:
Text.selectAll(); Text.copy(); Text.setSelection(0);
先全选 selectAll() ,然后用 copy () 方法将选中的内容复制到粘贴板,本来这样就可以了,但是这样子会出现选中的文字反黑的效果,所以为了不影响视觉效果,再用 setSelection (0) 将焦点放在起始位置。一瞬间执行三个语句是看不出的,呵呵,别遇上太卡的就不会影响效果。
当然可以用SWT 带的粘贴板类来实现功能。
用剪贴板类实现对系统粘贴板的访问
为了实现对剪贴板的访问,必须建一个剪贴板对象,如下:
Clipboard clipboard = new Clipboard(pasteButton.getDisplay()); String plainText = (String) clipboard.getContents(TextTransfer .getInstance());
啊,这个不知道怎么讲,记得同时要用到文本转换器和格式转换器,如果对格式没要求,则直接用文本转换器提取出你要的剪贴板板的文字。具体查API 吧,我也是边查API 边写的。如果要提出剪贴板的文字,只要上面两句就OK 了。
退出按钮
想做一个退出按钮,来实现跟系统退出一样功能的效果。监听器内容如下:
} else if (widget == cancelButton) {// 退出按钮 Shell shell = (Shell) cancelButton.getParent(); shell.close(); }
得到父亲之后,强转为Shell 类,然后调用 close ();
还有很多细节,待以后研究到继续记录