JVM桌面框架的状态:SWT


什么是SWT?

SWT源自Eclipse项目(IDE)。对于Eclipse,开发人员构建了专用框架来构建其图形组件。Swing和SWT的设计差异很大。Swing从头开始用Java实现小部件的绘制。相反,SWT是依靠本地图形对象的瘦包装API。这有两个主要好处:

  1. 小部件看起来是平台的本机
  2. 渲染速度更快

SWT API

SWT背后有一个指导原则:因为它依赖于本机图形对象,所以每个组件都需要一个“父”对象作为其第一个参数。父母是孩子被吸引到的对象。每个SWT组件的构造函数都将父级作为其第一个参数。

20210220121124.png

SWT的乐趣

SWT具有一些特性,其中大多数与基于系统库的设计有关。

本机依赖

SWT为每个主流操作系统(例如Windows,Mac OSX等)提供JAR 。例如,这是我的笔记本电脑的Maven依赖项:

pom.xml
<dependency>
  <groupId>org.eclipse.platform</groupId>
  <artifactId>org.eclipse.swt.cocoa.macosx.x86_64</artifactId> 
  <version>3.114.100</version>
  <scope>runtime</scope>                                       
</dependency>
  1. JAR坐标取决于平台。它包含JNI绑定形式的必需本机库。
  2. 仅在运行时需要JAR

swt-jar-structure.jpg

SWT事件控制循环 Swing提供了一个开箱即用的事件控制循环。SWT并非如此。我们需要将以下代码复制粘贴到我们的每个应用程序中:

val display = Display()                           
val shell = Shell(display)                        
shell.open()                                      
while (!shell.isDisposed) {                       
  if (!display.readAndDispatch()) display.sleep() 
}
display.dispose()
  • SWT与操作系统之间的桥梁
  • 创建顶层窗口
  • 显示它
  • 虽然窗口的系统本机资源尚未释放
  • 处理排队的事件。如果什么也不需要做...
  • 释放所有系统本机资源

无参数构造函数

窗口和对话框Shell在SWT中均表示为实例。顶级窗口不需要父级,因此Shell提供了一个无参数的构造函数。但是由于Shell是图形控件,因此其所有父类也都提供了这样的构造函数。这些构造函数的主体为空,调用它们不会执行任何操作。

组件创建顺序

在父对象上实例化组件的顺序就是将它们添加到该父对象的布局中的顺序。如果需要解耦它们,则需要发挥创造力,例如将对构造函数的调用包装在lambda中。

这是一个SWT示例,按此顺序显示标签,文本字段和按钮:

val label = Label(shell, SWT.LEFT)
val text = Text(parent, SWT.SINGLE or SWT.LEFT or SWT.BORDER)
val button = Button(shell, SWT.PUSH)

Styling

如上一片段所示,小部件的样式在其实例化期间发生。这些样式SWT以样式位的形式编码在类中:

  • LEAD = 1 << 14
  • LEFT = LEAD
  • SINGLE = 1 << 2
  • BORDER = 1 << 11
  • PUSH = 1 << 3

等等。

循环依赖

请注意,的构造函数Control采用一个Composite实例,该实例本身是的子类Control。这种循环依赖关系绑定到同一包中。

显示表格数据

SWT仅关注小部件及其渲染。与Swing和JavaFX相对,它没有数据模型的概念:您需要自己管理数据。对于0-D数据(例如文本字段),甚至对于1D数据(例如列表框),都是可管理的。对于二维数据,即表格,这很麻烦。

因此,大多数图形框架在组件与其管理的数据之间引入了模型抽象。例如,Swing具有JTable和TableModel。

Eclipse提供了JFace库,该库通过SWT API等提供了数据模型抽象。例如,对于表,JFace具有TableViewer类。每个JFace查看器类的核心都包含一个SWT控件。

20210220125228.png

包装在很深的层次上适用:SWTTableColumn被JFace的包装TableColumnViewer。

本Viewer类具有丰富的类型层次来处理不同尺寸的数据。IStructuredContentProvider提供多行数据,例如表中的数据。由于API是在泛型之前设计的,因此需要在StructuredViewer级别上进行运行时检查以验证set的类型IContentProvider。此外,StructuredViewer还提供了排序,过滤和“装饰”功能。

20210220125425.png

注意,有一个库可以管理模型和控件之间的双向数据绑定:JFace Data Binding。我找不到兼容的版本。

结论 不可否认SWT的成功。Eclipse不仅使用它,而且某些软件也使用它。

SWT提供了完全本地的外观GUI。从好的方面来说,这意味着应用程序具有本机行为。另一方面,与此功能相关的成本:

  1. 平台库的依赖项,这违反了“随处运行”的承诺
  2. 由于缺少泛型,因此运行时检查而不是编译时检查
  3. 由于上述两个原因,API有时会显得笨拙 非常感谢Benjamin Muskalla提出的这篇帖子的审查建议。

可以在Github上以Maven格式找到此帖子的完整源代码。


原文链接:http://codingdict.com