第1章:SWT 是什么?
作者:步子哥 (steper@foxmail.com)
1.1 三个比喻看懂 SWT
比喻一:翻译官与当地工匠
想象你是一个跨国公司的项目经理,
你只会说英语(Java),
但你的客户来自不同的国家:
- 美国客户说 Windows 话
- 德国客户说 Linux 话
- 日本客户说 Mac 话
现在你要为客户建造一栋房子(GUI 应用)。
Swing 的做法:
你自己画图纸,自己选材料,
虽然你用的是英文描述,
但画出来的门窗都是你"想象中的标准门窗"
到了美国,客户说:"这不是我们美国的门窗"
到了德国,客户说:"这不是我们德国的门窗"
SWT 的做法:
你聘请了一位翻译官(SWT 库),
你用英文(Java)告诉翻译官:"我要一个按钮"
翻译官转头对当地的工匠说:
- 在美国:"Make me a Win32 button"
- 在德国:"Make me a GTK button"
- 在日本:"Make me a Cocoa button"
工匠用他们最熟悉的材料和方法做出来,
客户一看:"这就是我们当地的按钮!"
关键点:
- 你(Java 开发者)不需要学习当地语言(Windows API、GTK API、Cocoa API)
- 翻译官(SWT)负责语言转换
- 当地工匠(操作系统)负责实际建造
- 最终呈现的是最地道的本地风格
比喻二:桥梁的两端
SWT 就像一座连接两端的桥梁:
┌─────────────┐
│ Java 世界 │
└──────┬──────┘
│ SWT (桥梁)
┌──────▼──────┐
│ 操作系统世界 │
└─────────────┘
Java 世界这一端:
- 语言统一:都是 Java
- 逻辑清晰:面向对象编程
- 跨平台:一份代码,多处运行
操作系统世界这一端:
- 风格各异:每个系统都有原生控件
- API 不同:Windows API、GTK API、Cocoa API
- 行为一致:用户期望与系统其他应用一致
桥梁(SWT)的作用:
- 提供 Java 语言的接口(让你用 Java 调用)
- 连接不同平台的原生实现(一次编码,自动适配)
- 保持轻量:桥面不宽,够用就行
为什么需要这座桥?
没有桥的情况:
- 你要跳河游过去(学习每个系统的 API)
- 每次都要重新造桥(每次写应用都要处理跨平台问题)
有了 SWT 这座桥:
- 轻松走过去(用熟悉的 Java)
- 桥已经建好了(SWT 团队维护)
- 多次往返都方便(多个项目共用)
比喻三:操作系统 API 的披萨外卖
把操作系统 API 想象成一家披萨店:
Windows 披萨店:
- 披萨(控件)用 Windows 风格的原料
- 点餐方式:用 Windows API 语言
- 送餐员:Windows 原生控件
Linux 披萨店:
- 披萨(控件)用 GTK 风格的原料
- 点餐方式:用 GTK API 语言
- 送餐员:GTK 原生控件
Mac 披萨店:
- 披萨(控件)用 Cocoa 风格的原料
- 点餐方式:用 Cocoa API 语言
- 送餐员:Cocoa 原生控件
现在你要吃披萨(开发 GUI 应用),但你只会说 Java。
SWT 的做法:
你用 Java 下单:"我要一个按钮"
SWT 外卖员接到订单后:
- 在 Windows:给 Windows 披萨店打电话(Win32 API)
- 在 Linux:给 Linux 披萨店打电话(GTK API)
- 在 Mac:给 Mac 披萨店打电话(Cocoa API)
披萨店用他们自己的方式做披萨,
SWT 外卖员把披萨送到你面前,
你吃到的就是最地道的当地风味!
类比的边界:
- ✅ 准确:API 调用确实像点餐,操作系统像餐馆
- ⚠️ 边界:SWT 不是"外卖员",更像"代理",你直接通过它访问原生控件,中间没有延迟
1.2 SWT 的前世今生
从 AWT 到 Swing 再到 SWT
GUI 库的进化史,就像技术的三次浪潮:
第一次浪潮:AWT(Abstract Window Toolkit)
时间:1995 年,Java 诞生之初
特点:用最笨的方式实现跨平台
方式:用"最小公约数"策略
- Windows 有按钮,Linux 有按钮,Mac 有按钮
- 找它们的共同点:"都叫按钮"
- 用最简单的按钮实现
问题:丑!太丑了!
- 看起来像 90 年代的 Windows 3.1
- 不同系统下外观不一致
- 功能有限,很多系统特性用不了
第二次浪潮:Swing
时间:1998 年,Java 2 发布
特点:完全自绘,不用系统的任何控件
方式:
- "我自己画按钮,不用你的!"
- 所有的控件都是 Java 画的
- 看起来一样(都丑一样,都美一样)
优点:跨平台完全一致,功能强大
问题:
- 感觉"不像"本地应用
- 性能不如原生
- 用户的肌肉记忆失效
(Mac 用户习惯了 Mac 的菜单栏,但 Swing 的菜单不一样)
第三次浪潮:SWT(Standard Widget Toolkit)
时间:2001 年,Eclipse 项目诞生
特点:拥抱原生,轻量封装
方式:
- "用系统最好的控件,用 Java 调用"
- 通过 JNI(Java Native Interface)连接
- 每个平台用对应的原生库
优点:
- 原生外观和手感
- 性能接近原生
- 用户感觉像本地应用
问题:
- 不同平台行为有差异(但这是特性,不是 bug)
- 需要分发平台相关的库
Eclipse 的诞生故事
2001 年,IBM 投入 4000 万美元,启动了一个秘密项目:
目标:打造一个统一的开发工具平台,取代 VisualAge
项目代号:Eclipse(日食,意为"遮蔽一切")
技术挑战:
- 当时 IBM 用的是 VisualAge for Java,基于 Swing
- Swing 的性能和外观都不够理想
- 用户体验不如 Visual Studio(Windows 原生)
关键决策:
IBM 决定:不用 Swing,自己做一个 GUI 库
为什么不用 Swing?
- Swing 太慢
- Swing 不像 Windows 应用(Visual Studio 对手)
- Swing 难以定制(IBM 需要深度定制)
SWT 的诞生:
- IBM 用 C++ 写了 Windows 原生库(.dll)
- 用 Java 写了统一的 API
- 通过 JNI 连接两者
- 后来又支持了 Linux(GTK)和 Mac(Cocoa)
开源的决定:
2004 年,IBM 将 Eclipse 捐赠给 Eclipse 基金会
从此,Eclipse 和 SWT 成为开源世界的瑰宝
费曼问题:为什么叫 Standard Widget Toolkit?
"Standard" 的含义:
- 不是"统一标准"(像 Swing 那样每个平台一样)
- 而是"使用平台的标准控件"
- Windows 用 Windows 标准,Linux 用 Linux 标准
"Widget Toolkit" 的含义:
- Widget 就是控件(按钮、文本框等)
- Toolkit 是工具包
- 合起来就是:操作标准控件的工具包
1.3 SWT vs Swing vs JavaFX
一张表看清三者的差异
| 特性 | AWT | Swing | JavaFX | SWT |
|---|---|---|---|---|
| 原生控件 | ✅ 部分使用 | ❌ 全部自绘 | ❌ 全部自绘 | ✅ 完全使用 |
| 外观 | 丑陋 | 可自定义但非原生 | 现代化但非原生 | 原生 |
| 性能 | 好 | 一般 | 较好 | 好 |
| 跨平台一致性 | 差(功能受限) | 好(完全一致) | 好(完全一致) | 差(行为有差异) |
| 学习曲线 | 简单 | 中等 | 中等 | 简单 |
| 打包部署 | 简单 | 简单 | 复杂(需要 JavaFX 模块) | 需要分发原生库 |
| 社区活跃度 | 停止维护 | 维护中 | 维护中 | 活跃(Eclipse 生态) |
| 适合场景 | 已淘汰 | 内部工具 | 现代化应用 | 桌面应用、IDE |
何时选择 SWT?
选择 SWT 的场景:
- 需要原生外观和手感
``
例如:
- Windows 用户希望应用看起来像 Windows 应用
- Mac 用户希望应用遵循 Mac 的设计规范
- Linux 用户希望应用与 GNOME/KDE 融为一体
``
- 性能要求高
``
例如:
- 需要频繁更新大量控件(如表格、树)
- 需要流畅的动画效果
- 需要处理大量数据
``
- 已有 Eclipse 插件生态
``
例如:
- 开发 Eclipse 插件
- 使用基于 SWT 的框架(如 RCP)
``
- 用户熟悉原生交互
``
例如:
- 企业内部应用,用户习惯了本地应用
- 工具软件,需要快捷键、菜单等原生特性
``
不选择 SWT 的场景:
- 需要完全一致的跨平台外观
``
例如:
- 品牌要求所有平台完全一致
- 需要高度定制的 UI
``
- 需要现代化 UI 特性
``
例如:
- 需要 CSS 样式支持
- 需要 3D 图形支持(JavaFX 更好)
- 需要动画和过渡效果(JavaFX 更丰富)
``
- 不想分发原生库
``
例如:
- 简单的内部工具
- 快速原型开发
``
1.4 SWT 的设计哲学
"原生优先":让应用像本地应用
SWT 的核心信念:
用户不应该知道你的应用是用 Java 写的。
用户的感觉应该是:
- "这是一个 Windows 应用"
- "这是一个 Mac 应用"
- "这是一个 Linux 应用"
如何实现?
- 使用操作系统的原生按钮、菜单、对话框
- 遵循操作系统的设计规范
- Mac:菜单栏在屏幕顶部
- Windows:菜单栏在窗口顶部
- 支持系统的快捷键
- Mac:Cmd+C 复制
- Windows/Linux:Ctrl+C 复制
- 支持系统主题
- Windows 遵循系统颜色
- Linux 遵循 GTK 主题
- Mac 遵循系统外观
费曼测试:
问一个 Mac 用户:"你觉得这个应用是用什么写的?"
如果他回答:"不知道,但感觉像 Mac 应用"
这就是 SWT 的成功。
如果他回答:"感觉不像 Mac 应用"
那就说明出了问题。
"薄薄一层":不重复造轮子
SWT 的设计理念:
只做必要的事情,不做多余的事情。
薄薄一层的含义:
- Java API → JNI → 原生库
- 中间没有臃肿的抽象层
- 直接调用系统 API,几乎零开销
对比 Swing(厚厚一层):
Java API ──→ Swing 实现 ──→ Java 2D ──→ 操作系统绘图 API
(自绘按钮) (自己画像素)
问题:
- 每次点击按钮,Swing 都要画像素
- 不是调用系统按钮,而是"假装"按钮
- 性能开销大
SWT(薄薄一层):
Java API ──→ JNI ──→ 系统按钮 API
(真正调用按钮)
优势:
- 点击按钮直接调用系统 API
- 系统按钮已经优化,性能好
- 代码量少,维护成本低
类比的边界:
- ✅ 准确:SWT 确实比 Swing 薄,因为不重复造轮子
- ⚠️ 边界:"薄"不等于"简单",适配多个平台本身就很复杂,但对使用者来说是"薄"的
"掌控与放手":在 Java 与系统之间平衡
SWT 的平衡术:
- 掌控:让开发者用 Java 控制一切
- 放手:让系统自己处理细节
掌控部分(Java API):
- 用面向对象的方式创建控件
- 用监听器处理事件
- 用布局管理器管理布局
- 用统一的 API 跨平台调用
放手部分(系统处理):
- 按钮的外观由系统决定
- 菜单的行为由系统决定
- 滚动条的表现由系统决定
- 快捷键由系统处理
例子:按钮的悬停效果
// 你只需要创建按钮,告诉它要做什么
Button button = new Button(shell, SWT.PUSH);
button.setText("点击我");
button.addListener(SWT.Selection, event -> {
// 处理点击事件
});
// 悬停效果(鼠标移上去变亮)由系统自动处理
// 你不需要写任何代码
如果用 Swing(需要掌控一切):
// 你需要自己处理悬停效果
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
button.setBackground(Color.LIGHT_GRAY);
}
@Override
public void mouseExited(MouseEvent e) {
button.setBackground(null);
}
});
SWT 的哲学:
能放手就放手,让系统做它擅长的事情
该掌控就掌控,让开发者控制应用逻辑
1.5 本章小结
三个比喻回顾
| 比喻 | 核心思想 | 伏笔(后续会展开) |
|---|---|---|
| 翻译官 | SWT 让你用 Java 调用原生控件 | 第 2 章会详细讲解 JNI 原理 |
| 桥梁 | SWT 连接 Java 世界和操作系统世界 | 第 13 章会讲解系统级集成 |
| 披萨外卖 | SWT 封装了原生 API 的复杂性 | 第 11 章会讲解资源管理 |
关键要点
- SWT 是什么?
- Standard Widget Toolkit(标准控件工具包) - 通过 JNI 调用操作系统原生控件 - 轻量级的 Java GUI 库
- 为什么选择 SWT?
- 原生外观和手感 - 性能好 - 适合桌面应用开发
- SWT 的设计哲学?
- 原生优先 - 薄薄一层 - 掌控与放手
下一章预告
现在你已经理解了 SWT 的本质,
下一章,我们将动手搭建环境,
写出你的第一个 SWT 程序。
就像学会了语言理论,
现在要开始实际对话了。
练习题:
- 用自己的话解释 SWT 和 Swing 的区别?
- 如果你是一个 Windows 用户,你会更倾向于使用 SWT 还是 Swing?为什么?
- SWT 的"薄薄一层"是什么意思?为什么这样设计?
(答案在本章中,自己找找看)