跨平台开发中 GUI 的重要性
在使您的程序跨平台时,关键问题是如何移植 GUI。一种解决方案是为每个平台编写单独的 GUI 前端。这为您提供了极大的灵活性,并让您可以为目标系统量身定制每个界面,但很快您就会发现您正在从头开始重写相同的界面想法。您开始怀疑是否应该抽象出一些概念,例如创建按钮或绘制线条,并使用该抽象来代替。这正是可移植 GUI 工具包已经做的事情。因此,您可能会选择一个 GUI 工具包,甚至希望能够改进它,而不是重新发明轮子或小部件。
提供平台独立的 GUI 功能有两种方法。封装器方法 封装 本地系统小部件在一个抽象层中,该抽象层在不同的系统之间提供通用功能。模拟或 纯 方法只是拦截本地绘图调用,然后使用这些调用来实现自己的小部件。
封装器更容易编程,因为您不必编写自己的小部件。本地目标平台的外观和感觉很容易保持,因为在封装器下,您正在使用本地系统小部件。但是,封装器也失去了灵活性,因为它们只能提供本地小部件已经提供的功能——一种“最低公分母”的移植方法。它们无法扩展。它们不允许您充分利用工具包的强大功能。
我个人更喜欢 纯 或 模拟 小部件,而不是本地封装器类。如果您对最新 Windows 版本中某些本地小部件功能印象深刻,您可能会担心模拟小部件会落后于那些本地封装的小部件。对我来说,情况恰恰相反。我认为模拟方法具有超越本地平台功能的灵活性。我相信,如果大多数免费 GUI 工具包制造商都在开发一个通用的“Linux GUI API”,我们将很快超越 Windows 和其他公司控制的 GUI 开发,凭借我们新的和模拟的小部件的卓越性。
我正在开发的程序需要完全支持多语言,包括相当复杂的中文、日文和韩文字符(汉字)的组合。我对 Windows 新的本地小部件功能没有留下深刻印象;它们远未达到我的需求。因此,使用小部件封装器,我基本上被困在基于 Canvas 小部件从头开始重写每个小部件,而使用 纯 小部件,我可以利用常用的面向对象技术来扩展现有的小部件(假设 API 设计良好)。这在编写 GUI 应用程序时提供了更大的灵活性和一致性。
对于 Linux 和 UNIX,本地小部件封装还有另一个问题;目前尚不清楚什么是本地小部件。在 Windows 和 Macintosh 中,这很明显。但是,UNIX 没有标准的 GUI API(除了 X 协议,它不是完整的 GUI)。UNIX 最接近的是 Motif,它实际上不是标准,也不是免费的。换句话说,在 Linux 世界中,即使在您考虑移植性问题之前,您首先必须选择一个 GUI 库。您必须确定哪些小部件将成为您的本地小部件。除了为 Linux 程序提供您想要的所有小部件和结构之外,您选择的 GUI 工具包还可以为跨平台开发提供帮助。而这正是您想要的。现在编程效率更高,因为您只需要掌握一套工具。
由于 C 和 C++ 非常流行,因此大多数工具包都具有 C 或 C++ 接口。事实上,大多数时候都是 C++,因为面向对象编程似乎特别适用于 GUI 代码。但是,有些工具包(例如 Fresco)试图保持语言中立,并可能为几乎任何语言提供接口。这些工具包以库的形式出现,必须为每个目标系统编译和链接。另一方面,有一些解释型语言,例如 Smalltalk、Tcl 和 Java,它们可以在多个系统上运行,而无需为每个系统编译。还有一些用 C 编写的工具包,例如 GTK,可以从许多其他语言(例如 Scheme、Python 或 Perl)调用。(请注意,GTK 目前不是跨平台的,但请参见下文。)
Linux 需要一个标准的 GUI API。并非所有应用程序都必须最终看起来甚至行为都像 Windows 那样,但它们在某些领域应该保持一致;例如,一致的桌面、一致的帮助系统、剪切和粘贴、拖放等等。
开发精力分散到过多的 GUI 工具包中是当今 Linux 社区面临的最严重问题之一。人们对这个问题的严重性有所认识,但没有人能够就使用哪个 GUI 工具包达成一致。Gnome 和 KDE 桌面项目就是一个很好的例子;Gnome 使用 GTK,而 KDE 使用 QT。
对于 Windows 和 Macintosh,这很简单;您别无选择。当然,我更喜欢 Linux 和 GNU 世界中蓬勃发展的混乱局面,而不是微软领域中令人窒息的独裁式一致性,但作为一名程序员,如果 GUI 工具包的选择是轻而易举的,那就令人满意了。如果存在“Linux GUI API”这样的东西就好了,这样 Linux 开发人员社区的协同作用可以更好地促进创新和引人注目的程序的创建,而不仅仅是创新的但未完成的工具。
与以 Linus 为中心的 Linux 内核开发形成对比的是,每个人对 GUI 工具包都有自己的想法,并朝着自己的方向前进。他们通常只完成 90% 的工作。一个新的工具包出现了,复制了前 90%,然后逐渐消失或被另一个工具包超越,后者向前冲锋,但从未达到目标。这些 GUI 工具包开发项目似乎无法维持添加最后 10% 所需的能量和支持。“最后 10%”的内容各不相同,但通常包括对国际化输入法和字体以及线程的支持。至少可以说,这令人沮丧。
如果由我来决定,Fresco 将成为每个人都在努力的首选工具包。但是,我无法强迫任何人这样做,我也无法独自完成。许多其他人,有不同的偏好,也处于类似的困境。
并非每个人都会赞同我的品味(轻描淡写),但以下是我对一些最有希望的候选工具包的简要介绍。请注意,我自己在跨平台开发方面的大部分兴趣都集中在 Linux (UNIX/X11) 和 Windows 上。如果一个解决方案也支持 Macintosh 和 OS/2,那只是额外的奖励。我偏爱免费且不受可憎的许可限制的工具包。“GUI 工具包、框架页面”上列出了大约 100 个 GUI 工具包,因此这显然只是一个小样本。
Fresco 是一个面向对象的用户界面工具包,由 Mark Linton 等人设计。Mark Linton 领导了斯坦福大学 InterViews 工具包的开发,他似乎从那次经验中学习了很多关于 GUI API 设计的知识。Fresco 是用 C++(Ada 和 Java 版本也可用)实现的,但编程接口是用 IDL(接口定义语言)编写的,因此它是语言中立的。Fresco 使用 CORBA 并支持分布式图形嵌入。它支持结构化图形和分辨率独立性。它支持 X、Windows 和 Macintosh。小部件实现通过 工具包 公开,这些工具包允许在每个平台上具有不同的外观和感觉;但是,仅实现了 Motif 外观和感觉。
使用 Fresco 可以非常容易地扩展小部件和编写新的小部件。我在几个小时内编写了一个简单但灵活的表格小部件。它使用字形 DAG(有向无环图)的概念,字形可以是图形、布局或小部件。DAG 包括完整的 2D 变换信息,这产生了一些令人印象深刻的演示。一个例子是一个绘图编辑器,它将自身的副本嵌入到绘图中,缩放和旋转,但仍然完全可用。它既酷又强大。对于布局,它使用 TeX 的盒子和胶水的概念,这也非常方便和强大。
但是,我猜 Fresco 是那种好得令人难以置信的东西之一。最初是作为新的 X 联盟标准的竞争者,赞助这项工作的公司已经放弃了它,商业 UNIX 正在转而使用 Motif。这给任何决定使用 Fresco 的人带来了很大的责任。如果您有任何需要,您可能必须自己编写。两个最大的缺失部分是对打印和系统剪贴板/选择的支持。Fresco 需要更多的小部件、更多的润色和更多的文档,即,它需要更多的人使用它和开发它。
我建议您即使不打算使用 Fresco,也要了解 Fresco 的设计。Fresco 可能只是超前于时代。期待 Fresco 中包含的一些概念在未来 10 年内被誉为全新的革命性技术。
OpenStep 是一个 GUI API(以及一些非 GUI 功能),最初基于 NextStep 系统。GNUstep 是 OpenStep 的免费实现。它仍在开发中,尚未真正达到可用的状态。
该 API 看起来高于平均水平。一个不错的特点是使用强大的 Display Postscript 进行屏幕绘图,这使得打印几乎变得微不足道。
最大的问题是它使用 Objective-C。我不想再学习一门语言,但在多年试图找到 GUI 工具包问题的最佳解决方案之后,我可能会。随着最近 Apple-Next 的炒作,OpenStep 可能会获得足够的动力和炒作,以至于将其用于自由软件可能会有所回报。Apple 已将 OpenStep 采纳为 MAC API 的未来方向,他们还将为 Windows 提供一个实现。但是,Apple 和 OpenStep 未来的成功尚不清楚。
GNUStep 在 LGPL 许可下获得许可,因此可以在免费和商业程序中使用。
wxWindows 是最早的免费 C++ 跨平台 GUI 工具包之一。它采用封装器方法来提供跨平台功能,在 X 上封装 Motif 或 XView,在 Windows 上封装 Windows 小部件。还有一个 wxWindows 较旧版本的 Macintosh 部分移植版本。
wxWindows 具有许多实用功能和大量的开发活动,但它也存在封装其他小部件库而不是实现自己的小部件库的缺点。它不如它可能的那样一致和灵活。不同的平台通常具有不同的功能和不同的错误,并且平台之间的开发并不总是同步的;因此,您必须小心确保您的程序实际上可以在所有平台上运行。
wxWindows 中编写了许多额外的高级小部件,例如表格和 HTML 查看器。wxWindows 还提供了一些更高级的架构功能,例如 Doc/View 和打印预览,尽管我个人尚未测试过这些功能。
如果您的程序不需要比跨平台简单本地小部件的通用功能提供的更高级的界面,那么 wxWindows 是一个不错的实用选择。
正在开发中的 wxWindows 新版本 2.0 将在 API 中进行一些更改,以使其更具功能性。还有一个项目旨在使 wxWindows 封装 GTK 小部件库,以及一个项目旨在实现使用 wxWindows 绘图调用的 通用 小部件。预测这些变化和新增功能将如何影响 wxWindows 的未来还为时过早。
Tcl/Tk 是 X 上 GUI 程序的流行解决方案,它已被移植到 Windows 和 Macintosh。Tcl 是一种简单的脚本语言,Tk 是一个可以与 Tcl 一起使用来创建界面的小部件集。我发现 Tcl 语言不是特别吸引人,Tk 与 Tcl 的联系也相当紧密,尽管正在努力更清晰地分离两者。还有其他语言的绑定,例如 Scheme、Python 和 Perl。但是,据报道,从 C 或 C++ 使用 Tk 有些笨拙。我注意到 Tk 应用程序往往相当迟缓,但我不知道这是因为 Tcl 还是 Tk 小部件本身。
Tk 的另一个缺点是,所有平台的外观和感觉(有点像 Motif)都相同,因此该界面对于 Windows 和 Macintosh 用户来说可能看起来不协调,尽管我听说正在努力补救这种情况。
尽管存在缺点,但 Tk 确实有很多功能齐全的小部件。据我所知,可以相对快速地创建界面。当然值得考虑。
一种编程语言、可移植虚拟机和库集合(称为包),这三项技术现在显然被称为“Java”。在过去的几年里,Java 受到了很多炒作。虽然虚拟机和严格指定的语言提供了一些小的可移植性功能,但 Java 最吸引我的部分是跨平台 GUI API。最初的 GUI API,称为 AWT,是一个简单的封装器库,没有什么特别的优势。但是,Sun 现在正在创建一组新的纯 Java 小部件,称为“Swing”,它看起来设计良好且功能齐全。凭借 Java 背后的所有炒作和动力,Swing 有可能成为可用的最佳 GUI 库之一。
当然,缺点是 Swing(JFC,Java 基础类的一部分)几乎与语言中立性背道而驰。如果您想使用 Swing,您必须使用 Java 语言和其他 Java 库,通常会放弃您完美现有的库。
我对 Java 最大的抱怨只是我觉得我不再真正为 Linux 开发了;相反,我正在为“Java 平台”开发。我对 Java 的潮流所产生的各种炒作和废话感到厌倦,我怀念 Linux 世界令人耳目一新的诚实。我也对 Sun 控制 Java 的方向感到不完全自在。如果我们在自由软件世界中不喜欢它的某些方面,那么最终我们无能为力,尽管 Sun 保证了 开放性。有 Java 语言和虚拟机的免费实现,但按照 Sun 创建 API 的速度,库的免费实现远远落后。
我希望能够使用高质量的 Java JFC 库,并且仍然与自由软件世界的发展方向保持一致。也许与 GNOME 项目合作,允许使用 Swing 的 Java 应用程序遵守 GNOME 应用程序策略会有所帮助。然后人们可以用 Java 编写 GNOME 应用程序,即使他们使用 JFC 而不是 GTK。
Qt 是一个商业 C++ 工具包,可用于 X 和 Windows。它在货币意义上不是免费的,X 和 Windows 版本都花费约 2200 美元。有一个特殊的例外:如果您为 X 编写 免费 程序,您可以免费使用它。但是,这个免费程序在 GNU 意义上或 Debian 自由软件指南意义上都不是真正的免费,这使得许多人(包括我)对基于 Qt 的项目持谨慎态度。
从技术上讲,Qt 设计得相当好。尤其值得注意的是其灵活的“信号和槽”事件处理方法。Qt 正在 KDE 桌面项目中使用。
Win32 是 Windows NT 和 Windows 95 的 API。由于其受欢迎程度,它也被用作跨平台 API。微软销售一个昂贵的软件包,允许您为 Macintosh 编译 Win32 程序。还有适用于各种 UNIX 版本的昂贵的 Win32 库。Wine(Windows 模拟器)项目正在尝试在 X 之上创建 Win32 的免费实现,以及一个直接运行 Windows 可执行文件的二进制模拟器。
使用 Win32 for Wine 的问题是 Wine 尚不够成熟,并且由于 API 由 Microsoft 控制,因此免费实现将始终落后于 Microsoft 自己的实现。Win32 显然是一个以 Windows 为中心的 API,它不是一个特别好的 API,因此使用它来开发 Linux GUI 程序并不是很令人兴奋。但是,如果您已经编写了很多 Win32 代码,或者已经非常熟悉该 API,那么值得考虑研究其中一个实现。
OSF/Motif 是一组商业库和小部件,构建在 X Toolkit Intrinsics (Xt) 之上,而 Xt 又构建在 Xlib 之上,Xlib 是 X 的最底层。在我看来,Motif 只是足够用。使用 Motif 创建应用程序很乏味,从用户的角度来看,Motif 也只是过得去,没有什么令人兴奋的。不幸的是,正是 Motif,而不是像 Fresco 这样技术上优秀的东西,商业 UNIX 供应商已宣布其为官方 UNIX GUI 标准(以及构建在 Motif 之上的通用桌面环境 CDE),这得到了 Open Group 的支持。
但是,仅仅被宣布为标准并不能使其成为现实。许多人不喜欢 Motif 的平庸质量,并使用其他解决方案来编程 X 应用程序。由于 Motif 不是免费的,因此它在 Linux 用户中不是很普及。Linux 发行版中包含的绝大多数 X 应用程序都不使用 Motif。因此,无论 Open Group 的法令如何,Motif 都不能真正被认为是明显的本地 UNIX GUI 库,就像 Win32 对于 Windows 和 QuickDraw 和 Toolbox 对于 Macintosh 一样。最好的说法是,大多数 X 工具包都倾向于提供一种与 Motif 有些相似的外观。
Motif 确实有一个优点;它确实提供了创建程序 GUI 中您可能需要的绝大部分内容的能力,即使这需要大量的时间和精力。Motif 具有最后 10% 的大部分功能,例如完整的键盘控制、用于自定义小部件的资源系统、对国际化输入法和字体以及线程程序的支持。
有一个免费的 Motif 实现可用,称为 Lesstif,它刚刚开始可用于某些应用程序。但是,它仍然需要努力才能提供最新版本的 Motif (2.1) 所具有的覆盖范围。有适用于 NT 的商业版本 Motif,尽管它们很昂贵,因此可以在跨平台应用程序中使用 Motif。我相信 Xlib 和 Xt 已经移植到 NT,并且理论上我假设 Lesstif 可以移植,这在理论上可以提供 NT 上的免费解决方案。
GTK 是 GIMP 工具包(参见 LJ 第 47 期),是在免费图像处理程序 GIMP 中使用的小部件库。(参见 LJ,第 43、44、45 和 46 期。)关于它最有趣的事情是,它似乎在 Linux 自由软件世界中获得了一些动力,因为越来越多的项目正在使用它。也许最值得注意的是 GNOME,一个旨在创建一个统一、一致的图形桌面环境的项目,该环境完全构建在自由软件之上。
在软件世界中,动力通常比技术设计更重要,因此仅凭这一点就值得研究 GTK。并不是说 GTK 在技术上很差。它是一个相当低级的工具包,用 C 编写,因此它没有提供很多高级支持。在 C 中实现面向对象设计的尝试在代码中创建了大量繁琐的工作,这有点分散注意力。但是,由于它是用 C 编写的,因此几乎可以使用任何语言,并且已经有 C++、Guile、Scheme、Objective C、Perl 以及可能还有其他语言的绑定。毫无疑问,这是 GTK 受欢迎的原因之一。
设计看起来合理。它不如 Fresco 灵活,但至少它在某些基本方面做得对,例如让按钮包含一个小部件而不是一个字符串。它还提供了使用水平和垂直框的布局,虽然我发现这些方法不如 Fresco 的 TeX 启发式的盒子和胶水直观,但它们仍然提供了一个相当简单的界面。
对于处理事件,GTK 使用类似于 Qt 的信号和槽系统。GTK 的 C++ 接口,称为 GTK--,也提供了使用模板的信号/槽方法的良好实现,这比 Qt 的宏有所改进。
GTK 仍然不成熟。它缺乏对完整键盘控制、资源系统、统一打印界面和国际化输入和显示的支持。它目前也仅适用于 X。它是在围绕一些 Xlib 函数的低级、薄封装器 GDK 之上实现的。这可能会使移植到其他系统变得更容易,但如果封装器非常薄,需要 Xlib 语义,则可能会更难。我在此处包含它的原因是,理想情况下,最好的 Linux GUI 工具包也将是一个跨平台 GUI 工具包。我希望随着 GTK 成熟为 Linux GUI 工具包的更明显选择,它也将成为跨平台解决方案的更明显选择,我们将不会有如此多的碎片化和重复劳动。
简而言之,我在各种工具包中没有找到明显的赢家。我现在正在使用 Java 和 Swing 包,同时更详细地研究 GTK 和其他工具包。啊,是的,我仍然梦想着 Fresco 会像凤凰一样从灰烬中重生。
Michael Babcock 自 1992 年以来一直使用 Linux。他的编程兴趣包括多语言软件(尤其是中文和日文)、解析技术、图形以及任何有助于改进和推广 Linux 的东西。他喜欢打篮球、弹吉他和听 The Fall 乐队的音乐。他预计将于 1998 年 5 月毕业于蒙大拿大学,获得计算机科学学士学位。可以通过电子邮件 michael@kanji.com 与他联系。