SWT体验之旅

本文介绍了IBM开发的SWT(Standard Widget Toolkit),一种用于Eclipse的Java GUI库。与Swing和AWT相比,SWT提供了更为简洁高效的事件处理机制,并详细讲解了如何创建基本的应用程序、事件监听和多线程操作。
SWT(Standard Widget Toolkit)是IBM公司为了开发Eclipse用C语言和C++开发的一套Java GUI库。SWT跟Java标准类库中的Swing和AWT有着本质的区别,这一点绝不仅仅是将Frame和JFrame改名为Shell这样表面的东西,从实现机制上讲,SWT从线程、事件监听等各方面都是一个完全新的世界。

另外,推荐使用Eclipse IDE来进行下面的体验——似乎在命令行无法运行SWT程序?SWT和Eclipse IDE都可以在 Eclipse官方站点 上下载。开发时,将swt.jar包导入到项目构建路径(Build path)中即可。

第一个SWT程序:

仍旧以著名的HelloWorld为例,如果你曾经用过Swing/AWT来写,也许你的代码中最后几行是

frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();

一个JFrame/Frame在设置可见以后实际上就创建了一个新线程,从逻辑上来说这是有问题的,因为程序员只是想让这个窗口可以被看到而已,但是这个窗口越俎代庖做了一些出轨的事情,结果就是额外的线程交织在一起让整个程序变得非常混乱。

现在看看SWT的HelloWorld吧

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class HelloWorld {
public HelloWorld() {
final Display display = new Display();
final Shell shell = new Shell(display);

final Label helloText = new Label(shell, SWT.CENTER);
helloText.setText("Hello,World!");
helloText.setFont(new Font(display, "Courier New", 14, SWT.BOLD));
helloText.pack();

shell.pack();
shell.open();

while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}

public static void main(String[] args) {
new HelloWorld();
}
}

首先你一定会注意到在构造方法最后的那个while循环,如果你将它去掉,程序也可以运行,然后一闪而过并终止掉。也就是说这个循环是维持窗口线程存在的语句。但是请注意,这个while循环不是随意写的,加入你写成

while (true);

那么程序窗口就会进入无限循环,它倒也确实不会消失,然而却会失去响应。所以在这里readAndDispatch()方法是重要的!
这个方法是org.eclipse.swt.widgets.Display的成员方法,而不是org.eclipse.swt.widgets.Shell的方法,我认为这两者的区别并不是Frame与Panel之间的区别,而更像Container与LayoutManager之间的区别。
另外,你也不需要为窗口来设置诸如DefaultCloseOperation之类的属性了,如果你想要在窗口关闭后做些什么,只需要在while循环后面添加就可以了,这样就把更多的自由留给了开发者。

也许你还注意到了我的一个小动作:设置了一下标签的字体。这里可以看到,SWT不像Swing有些地方还是用AWT的一些库,而是使用自己完全独立的一套GUI库,包括字体在内,与AWT/Swing平行。

给Swing/AWT开发者:Font的构造方法多了一个参数Device,另外字号参数和字样式参数的顺序与AWT相反;另外,很多常数量都在SWT这个类中以静态常量给出,包括诸如BUTTON1之类处理按键事件的常数全部在SWT类中,也有一些其他的类中包含常数,使用时最好通过文档来查找。

事件监听:

Swing中对事件的处理可以算上混乱了,ActionListener、MouseListener、MouseMotionListener——当你要往一个JButton上增加监听者以响应按下按钮的事件,你会选择谁?当你要关掉一个窗口时,你会选择实现WindowListener.windowClosed还是WindowListener.windowClosing?事件监听者的大部分方法是空着的,为什么我只需要响应其中的一种事件,却要实现所有的方法来白白增加代码的长度——以及混乱程度?

幸好这一切噩梦都会在SWT中被终结掉,在SWT的事件监听机制中,对事件的监听只有一个接口:
org.eclipse.swt.widgets.Listener
而这个监听者内仅有一个需要实现的方法:
public void handleEvent(org.eclipse.swt.widgets.Event event)
好了,所有的复杂烦恼都在此刻终结了,现在的问题是,这个东西这么简单,那么怎么知道是哪种类型的事件呢?

答案很简单,在org.eclipse.swt.widgets.Widget中的方法
public void addListener(int, org.eclipse.swt.widgets.Listener)
我们可以看到跟AWT/Swing中不同的是,这里还需传入一个整数,这个整数决定了响应何种类型的事件,比如:

final org.eclipse.swt.widgets.Button button =
new org.eclipse.swt.widgets.Button(shell, SWT.CENTER);

button.setText("Exit");
button.setSize(120, 50);
button.setLocation(200, 0);

button.addListener(SWT.MouseUp,
new org.eclipse.swt.widgets.Listener() {
@Override
public void handleEvent(Event event) {
shell.dispose();
}
} /* anonymous inner class */ );

在你的代码中合适的位置加入这样一段,再来运行一下试试。常量SWT.MouseUp预示着这次加入的事件监听对象需要相应鼠标点击事件(注:SWT内似乎没有MouseClick之类的常量,故使用MouseUp替代之)。
这对于开发人员来说是一种莫大的福音:也许某个按钮、某个菜单项、某个热键操作它们响应事件后执行相同的操作(典型的就是从文本框复制文本),这样只需要实现一个Listener,然后向所有需要的控件中添加就可以了——AWT事件监听者由于类型纷繁,很可能能丢给按钮而不可以绑定热键操作。

多线程:

也许这有一点不好,然而不要乱使用,或者根本撇开Thread来操作与SWT相关的多线程,否则程序会产生奇怪的异常。
这里有一个例子,假如我们试图通过多线程的方法在程序执行了1秒以后将button换个位置,使用Thread来操作通常应该这样:

new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
button.setLocation(0, 200);
shell.pack();
}
} /* anonymous inner class */ ).start();

然而事情并不像我们想象的那样,而是在控制台输出了一串异常:
Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid thread access
不过SWT给了我们另外的方法,那就是
org.eclipse.swt.widgets.Display
类中的方法
public void asyncExec(java.lang.Runnable)

public void syncExec(java.lang.Runnable)
以及
public void timerExec(int, java.lang.Runnable)
最前面那个方法是同步线程执行,也就相当于就地使用Thread来start一个线程,比如刚才的例子,改成

display.asyncExec(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
button.setLocation(0, 200);
shell.pack();
}
} /* anonymous inner class */ );

就可以了。而第二个则是异步线程执行,也就是说调用了这个以后,该Display将在一段时间中无法操作、不响应事件,直到该线程执行结束,大家可以简单地将上面的
asyncExec
中的a去掉试试。而最后一个则是定时同步线程执行,第一个参数单位为毫秒,在经过这么一段时间以后才开始执行线程,并且是同步线程(似乎没有定时异步线程?),还是以刚才那个为例:

display.timerExec(1000, new Runnable() {
@Override
public void run() {
button.setLocation(0, 200);
shell.pack();
}
} /* anonymous inner class */ );

这样就不用再去try-catch了。

今天的SWT体验之旅就到这里了,希望在简单的介绍后SWT能够激发你使用Java语言开发GUI桌面应用程序的兴趣。
【无人机】基于改进粒子群算法的无人机路径规划研究[和遗传算法、粒子群算法进行比较](Matlab代码实现)内容概要:本文围绕基于改进粒子群算法的无人机路径规划展开研究,重点探讨了在复杂环境中利用改进粒子群算法(PSO)实现无人机三维路径规划的方法,并将其与遗传算法(GA)、标准粒子群算法等传统优化算法进行对比分析。研究内容涵盖路径规划的多目标优化、避障策略、航路点约束以及算法收敛性和寻优能力的评估,所有实验均通过Matlab代码实现,提供了完整的仿真验证流程。文章还提到了多种智能优化算法在无人机路径规划中的应用比较,突出了改进PSO在收敛速度和全局寻优方面的优势。; 适合人群:具备一定Matlab编程基础和优化算法知识的研究生、科研人员及从事无人机路径规划、智能优化算法研究的相关技术人员。; 使用场景及目标:①用于无人机在复杂地形或动态环境下的三维路径规划仿真研究;②比较不同智能优化算法(如PSO、GA、蚁群算法、RRT等)在路径规划中的性能差异;③为多目标优化问题提供算法选型和改进思路。; 阅读建议:建议读者结合文中提供的Matlab代码进行实践操作,重点关注算法的参数设置、适应度函数设计及路径约束处理方式,同时可参考文中提到的多种算法对比思路,拓展到其他智能优化算法的研究与改进中。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值