使用 Tcl/Tk 进行 GUI 脚本编程
尽管许多 Linux 开发者现在才开始发现脚本语言和图形用户界面 (GUI) 工具包的结合,但这种开发环境并不新鲜。像 PyQt 和 pyGTK 这样项目的很大程度上不为人知的先行者是 Tcl/Tk,其最初的足迹可以追溯到 Linux 甚至被创建之前。在热情的社区支持下,多年来,Tcl/Tk 一直在为 UNIX、Windows 和 Macintosh 开发者 тихо 且高效地提供跨平台 GUI 脚本编程。
该语言本身目前已更新至 8.4.5.0 版本,而 Tcl/Tk 应用程序开发的首选工具 Visual Tcl 在经过两年的开发后,最近也已更新至 1.6 版本。本文着眼于该语言、工具包和 Visual Tcl,并描述了如何使用它们为实际需求生成简洁的解决方案。
尽管在脚本编写者蜂拥而至 Perl 以驱动新兴互联网时,Tcl 在某种程度上被忽视了,但 Tcl 在技术上仍然可以与 Perl、Python 或任何其他同类语言相媲美。它通常被描述为互联网保守得最好的秘密,它是一种免费(在所有最好的意义上)、功能齐全的语言,由字节码编译器驱动,其性能与任何同类语言相当。它在其他脚本语言使用的所有地方都被使用:系统管理、任务自动化、服务器后端,以及我们稍后将看到的应用程序开发。
作为一种编程语言,Tcl 非常容易学习。与 Python 和 Perl 复杂的特性集和语法相比,Tcl 在本质上是过程化的和直接的。整个语法完全用 11 条规则描述,整个语言都建立在这些规则之上。具有讽刺意味的是,正是这种简单性有时会使 Tcl 的新手感到困惑。有经验的程序员可以在十分钟内学会阅读 Tcl 脚本,并在一个小时内编写它们。初学者也不需要花费太长时间。
文档质量一流,以全面且编写精良的 man 手册的形式提供。还提供了完整的 HTML 文档包。如果 man 手册对新用户来说有点令人生畏,那么关于 Tcl/Tk 的书籍也相当丰富,其中最好的可能是 Brent Welch 最近更新的 Prentice-Hall PTR 出版的 Practical Programming in Tcl and Tk。同样值得一提的是 Tcler's Wiki,它是互联网上最大且支持最好的 Wiki 之一。
Tcl 的理念围绕一个思想:它是一种可扩展的语言。大多数语言允许开发者编写函数和过程,但 Tcl 更进一步。Tcl 允许开发者使用新命令和功能扩展整个语言,直至并包括添加基本语言结构,例如面向对象。Tk 工具包实际上是 Tcl 语言的另一个可选扩展,它恰好提供了一整套 Tcl 命令来创建、驱动和控制 GUI 小部件。与数十个其他扩展一样,Tk 长期以来一直包含在 Tcl 核心发行版中,现在更多地被视为语言的一部分,而不是它的扩展。
为了试用最新版本的 Tcl/Tk 和 Visual Tcl,我需要一个小项目来开发。一个个人需求恰好提供了这样的东西。自从有了数码相机以来,我一直想快速将几张照片放到网页上,以便亲朋好友可以看到它们。一个成熟的网络相册应用程序会显得过分;我只需要能够选择一两个图像文件,添加几行文本,然后出现一个我可以上传到 Web 服务器的单个网页。图 1 显示了我希望能够生成的页面类型的示例。
这种类型的项目是基于 GUI 的脚本的理想候选者。这是一个相当简单的任务,不依赖于速度,但显然受益于拥有图形用户界面。GUI 的功能很简单:向用户呈现一个界面,让他们选择一些图像文件,并在必要时查看它们,并收集几行随附文本。然后,脚本可以使用标准工具来生成 HTML 页面。在本例中,该工具是几乎每个现代 Linux 系统上都提供的 libxml2 包中的 XSLT 处理器。
本文的其余部分将介绍如何结合使用 Tcl/Tk 和 Visual Tcl 来快速开发这个小程序。图 2 显示了最终脚本的运行情况;代码可以从本文末尾提供的链接下载。
大多数 Linux 发行版都附带 Tcl/Tk。但是,我总是安装和使用 ActiveState, Inc. 的最新版本的 ActiveTcl。除了是最新的且专业呈现之外,它还提供了一个标准的 Tcl 包,其中包含许多有用的扩展。如果您知道您的用户正在使用 ActiveTcl,您就可以确切地知道他们在机器上安装了哪些扩展,因此可以保证您的脚本可以运行。我鼓励任何想要运行本文中项目的人下载并安装 ActiveTcl-8.4.5.0 或更高版本,因为这就是我用于开发的版本。ActiveTcl 带有自己的安装程序,如果您将其安装在例如 /opt/ActiveTcl-8.4.5.0 中,它不会干扰任何现有的 Tcl/Tk 安装。如果您在 /usr/bin 中已经有一个 Tcl/Tk 包,请确保您在用户帐户的 PATH 中设置一个较早的条目,以指向 ActiveTcl bin 目录。
Visual Tcl 可从 SourceForge 获得,并且也带有自己的安装程序。许多 Linux 发行版都包含它,但请确保您拥有最新版本。
Tcl/Tk 脚本编程的常用方法是从设计 GUI 开始。这个过程允许开发者仔细考虑应用程序所需的所有功能,并生成一个可以构建这些功能的坚实框架。当事情开始变得复杂时,这种方法就会崩溃,并且需要更正式的东西,例如模型、视图、控制器模式。但对于小型应用程序,例如我的网页,或对于快速原型设计,将 GUI 组合在一起是一个很好的起点。因此,我将从 Visual Tcl 开始。
开发者坐在文本编辑器前,仅凭脑力手动排列按钮、列表框和其他小部件的日子已经基本过去了。这种工作应该使用图形工具来完成。拖放小部件使开发速度更快,尤其是对于初学者而言。
Visual Tcl 正好提供了这些类型的工具以及其他一些工具。实际上,它似乎不太确定是否要表现得像一个精简的集成开发环境 (IDE)。它偶尔会提供一个文本编辑窗口,用户可以在其中编写构成实际应用程序的 Tcl 代码,而不是将自己限制在处理 GUI 的开发上。另一方面,它不提供调试器或其他传统的 IDE 功能,因此很难证明将其称为真正的 IDE 是合理的。我通过进入应用程序的配置对话框并关闭许多似乎妨碍我的功能(图 3)来处理这种个性混淆。
相反,我选择在我喜欢的环境 (XEmacs) 中编写应用程序逻辑的大部分内容,并且仅将 Visual Tcl 的输出用作一个库,该库为我的脚本创建 GUI。Visual Tcl 因其足够的灵活性而值得称赞,可以按照我选择的方式使用。清单 1 显示了我的包装器脚本,它是应用程序代码本身的起点。
清单 1. 一个简单的包装器,用于将 Visual Tcl 代码(在 gui.tcl 中)与主脚本分开。#! 行的怪异之处是启动 Tcl/Tk 脚本的常用方法。
#!/bin/sh # the next line restarts using wish \ exec wish "$0" "$@" # # My own procedures and "pre-gui" code will go here # # Load and run the GUI code created by Visual Tcl # source gui.tcl # # Any "post-gui" code I need can go here #
一旦我理解了我想要使用该工具的方式,我就很快生成了我想要的输出。小部件使用简单的点击界面放置,而单独的属性编辑器窗口允许对小部件行为的细节进行调整和摆弄,以满足用户的需要。当您理解 Tk 小部件布局设备时,它们也很容易控制。图 4 显示了 Visual Tcl 开发环境。
Visual Tcl 生成可执行的 Tcl/Tk 代码,这些代码可以直接加载和编辑。加载 Tcl/Tk 代码的例程非常宽容,这意味着开发者可以独立编辑和调整生成的代码,然后再返回到 Visual Tcl 以进行进一步的工作。
Visual Tcl 最大的问题是其背后工具包的过时性质。Tcl/Tk 仅提供小部件的基本构建块。像组合框和笔记本这样的东西在 Tk 中是不可用的。幸运的是,许多 Tcl/Tk 的扩展提供了这些巨型小部件,而 Visual Tcl 支持所有这些扩展。缺点是,为了使最终脚本正确运行,目标机器需要安装巨型小部件扩展。对于这个项目,我使用了 incr tcl 小部件集,而作为大多数 Linux 发行版一部分安装的 Tcl/Tk 可能不包含这个集合。因此,我推荐 ActiveTcl Tcl/Tk 发行版。事实上,我的 SuSE 8.1 系统确实包含 incr tcl,但奇怪的是不包含加载 JPEG 图像所需的扩展——我认为这是 SuSE 的一个相当明显的疏忽。
任何使用过真正流畅的 GUI 构建器工具(例如出色的 Qt Designer)的人都可以告诉您,Visual Tcl 需要做更多的工作。在我的双 PIII-500 机器上,它的速度很慢,令人恼火,并且它有相当多的可用性问题和错误,尽管这些问题应该在 point-one 版本中得到解决。但最重要的是,Visual Tcl 完成了我需要的工作。它生成的脚本足够可读,可以手动微调,并且代码所做的任何事情都可以被主应用程序中更具体的代码覆盖。我的 GUI 完成后,我继续进行项目的应用程序开发方面。
使 Tcl 与更现代的 GUI 脚本解决方案区分开来的是 Tk 工具包与执行工作的 Tcl 代码交互的方式。像 GTK 或 Qt 这样的包是底层库,用 C 或 C++ 编写。它们的脚本级绑定工作得相当好,但是从脚本语言到 GUI 工具包的 API 总是有一个很大的下降。开发者真的需要理解他们正在使用的小部件,并且必须知道如何使用直接对小部件本身的底层调用来配置和询问它们。
Tcl 和 Tk 之间的关系更像是对等性质。GUI 工具包与驱动它的语言在同一级别上运行,这使得组合易于使用。以包含要放入网页的图像列表的列表框小部件为例。在 Visual Tcl 中,呈现了列表框小部件的一个属性,称为 listvar,我将其设置为一个名为 ::imageList 的变量。::imageList 是我的 Tcl 代码中的一个列表变量,Tcl/Tk 确保其内容始终反映在列表框小部件中。如果我在该列表变量中添加、移动或删除一个项目,列表框小部件的内容会立即自动更新以显示其内容。处理图像列表的代码根本不访问或与 GUI 交互。它只是将单个列表变量保持在正确的状态,并确信 Tcl/Tk 会完成其余的工作。图 5 显示了这种关系。
有时需要更直接地访问小部件。在这些情况下,Visual Tcl 使用别名。在 Tcl/Tk 中,小部件的名称取决于它在小部件树中的位置。当添加和删除容器小部件(例如框架)时,该名称会更改。为了防止脚本编写者必须跟踪重要小部件的完整名称,Visual Tcl 允许用户指定别名——小部件始终以其知道的简短、易于记忆的名称。这些简短名称可以在全局关联数组(也称为哈希或字典)中查找,因此无论它们最终在哪里,都可以轻松访问小部件。例如,我给 Introduction 文本小部件起了别名 IntroText。要获取该小部件中当前的文本,可以使用清单 2 中的代码。
清单 2. 获取别名小部件的内容
... set introWidget $::widget(IntroText) set text [$introWidget get 1.0 end] ...
::widget 数组由 Visual Tcl 生成的代码自动提供,因此获取文本小部件的真实名称很简单。要求小部件提供从第 1 行字符 0 到结尾的当前文本也很容易。
查看器窗口中的图像显示实际上是对话框中心的标签小部件。Tk 可以从磁盘加载图像并用一行代码从中创建像素图。当用户选择一个新的图像文件时,会从中创建一个像素图,并使用一个命令将标签小部件设置为显示该图像(清单 3)。在实际脚本中,我将加载的像素图存储在缓存中。这使得从一个图像切换到另一个图像并再次切换回来更加清晰。
清单 3. 图像从磁盘加载,然后配置标签小部件以显示该图像(Tk 标签显示图像以及文本)。图像立即出现在屏幕上。
... set loadedImage [image create photo -file $filename] $::widget(ImageLabel) configure -image $loadedImage ...
当用户单击“发布”按钮时,将调用一个 Tcl 函数来创建网页。此代码的工作原理与此处无关。只需说明 Tcl 允许使用 TclXML 扩展生成 XML DOM,然后允许调用 libxml2 XSLT 处理器,后者生成 HTML。当然,让专业的软件包来完成繁重的工作是脚本编写者的王牌。
尽管 Tcl/Tk 脚本运行良好,但很难忽视 Tcl/Tk 脚本的外观与更现代的 Qt 或 GTK 脚本之间的明显质量差距。基于 Qt 和 GTK 的程序看起来比那些使用 Tk 小部件的 Motif 风格的程序更清晰,而且它们是可主题化的,而 Tk 则不是。还可以比较内置功能,例如文件选择器对话框——Tk 的文件选择器对话框并不比 GTK 的好,而且两者都因 Qt 的文件选择器对话框而相形见绌。Tcl 社区正在继续努力解决这些类型的问题,但与许多成熟的技术一样,由于担心破坏现有代码,改进进展缓慢。
Tcl/Tk 是当今常用的启用 GUI 的脚本语言中最古老的语言,但它不再享有过去那样的垄断地位。Python 与 GTK 或 Qt 相结合,现在为 Tcl/Tk 过去是自然选择的许多问题提供了更现代的解决方案。在外观、功能和桌面集成方面,Tcl/Tk 和 Visual Tcl 都有一些需要弥补的地方。然而,成熟且完美集成的 Tcl 语言和 Tk 工具包组合提供的应用程序开发的简易性仍然是首屈一指的。如果您有一个简单的脚本任务,可以从 GUI 中受益,并且开发速度和成本很重要,那么 Tcl/Tk 仍然应该是该工作的首选之一。
资源
ActiveState Tcl 网站:www.activestate.com/Products/ActiveTcl
Incr Tcl: incrtcl.sourceforge.net/itcl
Practical Programming in Tcl and Tk,第 4 版,作者 Brent Welch。Prentice-Hall PTR: www.beedub.com/book
Tcl 语法的 11 条规则:www.tcl.tk/man/tcl8.4/TclCmd/Tcl.htm
本文中开发的脚本的源代码:ftp.linuxjournal.com/pub/lj/listings/issue119/7225.tgz
Tcler's Wiki: mini.net/tcl
Tcl/Tk 总部:www.tcl.tk
Tcl/Tk man 手册,在线和可下载:www.tcl.tk/man
Visual Tcl: vtcl.sourceforge.net
libxml2 的 XSLT: www.xmlsoft.org/XSLT.html
Derek Fountain 是一名自由软件开发者,专门从事 UNIX 和 Linux。他坚信“尽可能简单,但不能更简单”这句格言。这就是为什么他尽可能部署脚本解决方案。他住在澳大利亚西部的珀斯。