使用 XView 编程

作者:Michael Hall

在计算机世界中,存在许多窗口系统——有些正在控制桌面,而另一些在工作站领域仍然很强大。正如我们大多数人更喜欢用高级语言而不是汇编语言编程一样,XView 为我们提供了一种高级的 GUI 开发方法。XView 组件带有默认设置,这些设置是有意义的,因此,例如,一个新创建的按钮一旦被创建出来,就会看起来和表现得“正确”。XView 的 API 既简单又广泛。简单是因为我们只需使用三个不同的库例程就可以完成大多数工作,而广泛是因为我们可以使用这些例程控制几乎每个组件的各个方面。

第一步

让我们直接进入主题,看看 列表 1 中所示的简单 XView 程序。确保您的系统上安装了 XView 和 OpenLook 库;否则,您将收到编译错误。将此示例放入名为 sample.c 的文件中,并使用以下命令进行编译

cc -o sample -I$OPENWINHOME/include\
-L$OPENWINHOME/lib\
-L/usr/X11/lib sample.c -lxview -lolgx -lX11

其中 OPENWINHOME 是您的系统上 OpenWindows 的主目录,通常为 /usr/openwin。

当您运行 sample.c 时,您将看到一个简单的文本编辑器,这是标准 XView 文本子窗口组件的功能。在文本窗口中键入内容,使用键盘光标键移动。使用鼠标单击和拖动来高亮显示单词、行和段落。鼠标右键弹出一个菜单,用于打开、保存和插入文件、退出文本和搜索字符串。抓住滑块的末端停止器并将其向下拉——您现在拥有同一文本的两个视图。

这真是太棒了,但我们是如何实现这一点的呢?让我们一起浏览一下示例程序。

首先,我们包含了两个头文件:一个用于通用的 XView 信息,另一个用于文本子窗口组件。如果我们有其他组件(可能是一对用于打开和保存文件的按钮),我们还将包含这些面板组件的头文件。

接下来,在我们的 main 例程内部,我们声明了一个 Frame 变量,XView 使用它来放置其他组件。它成为我们的文本子窗口和窗口管理器提供的窗口装饰之间的不可见层。

接下来,我们调用 xv_init 来初始化 XView 并将命令行参数传递给它。(查看 xview 手册页以获取所有命令行选项。)通过这个 xv_init 调用,我们首先遇到了一个贯穿所有 XView 调用的强烈主题——一个以 null 结尾的属性、值对列表。xv_init 的第一个参数在 XView 头文件中定义。xv_init 希望看到另外两个参数:main 的参数计数的地址和参数值。为了告诉 xv_init 我们没有其他事情要做,我们传递最后一个参数 NULL 来终止参数列表。

在下一行,我们使用 xv_create 创建我们的框架。在第一个参数中,我们指定此组件的父组件。由于我们只是创建最外层的框架,因此我们没有父组件,我们使用 XV_NULL。第二个参数指定我们要创建的组件类型,在本例中是 FRAME。请注意,其余参数形成一个以 null 结尾的后续属性、值对列表。例如,以下属性、值对

FRAME_LABEL, argv[0]

设置框架的标签,该标签将成为窗口标题栏上的文本。如果我们想设置框架在屏幕上的大小,我们只需添加两对来设置宽度和高度(在终止 NULL 之前)

XV_HEIGHT, 200,
XV_WIDTH, 400,
类似的属性用于设置框架的最大和最小尺寸、屏幕上的初始位置、页眉和页脚等。

继续,我们创建文本子窗口。我们将我们的框架变量传递给这个 xv_create 调用,因为我们希望框架成为文本子窗口的父组件,从而影响其大小和位置。我们正在创建的组件类型是 TEXTSW,表示文本子窗口,我们没有向其添加其他选项(尽管有很多可用选项)。

接下来,我们调用 xv_main_loop,它处理屏幕上出现的窗口的所有 X 事件。它调用较低级别的 xlib 例程来创建窗口、滑块和画布。它监听鼠标和键盘输入并处理它们。xv_main_loop 在窗口被用户关闭之前不会返回。那时,我们的程序可以静默退出。

在我们继续之前,还有两个重要的 XView 例程我们需要了解:xv_setxv_get。顾名思义,它们用于设置和获取 XView 组件的属性值。

在 sample.c 中,我们看到了如何在创建框架时设置其大小。我们也可以在创建后使用 xv_set 调用以这种方式设置大小

xv_set(frame,
        XV_HEIGHT, 200,
        XV_WIDTH,  400,
        NULL);

虽然垂直格式不是必需的,但它更清楚地显示了正在发生的事情:即,使用 frame 组件,我们将其高度设置为 200,宽度设置为 400。

假设在程序中的某个时候,我们需要确定框架在屏幕上的位置

int     x, y;
x = (int)xv_get(frame, XV_X);
y = (int)xv_get(frame, XV_Y);

这个代码片段检索框架在屏幕上的 x 和 y 坐标。是的,看起来我们违反了使用以 null 结尾的列表的规则,但由于 xv_get 返回单个值,我们只获取一个属性;因此,xv_get 只接受两个参数。

带有回调的第二个版本

让我们通过向此示例程序添加两个按钮来扩展它。一个按钮将向文本子窗口插入一个固定的文本字符串,另一个按钮将擦除文本子窗口。为此,我们将需要一个放置它们的位置:即,一个控制面板,它在 PANEL 包中实现。按钮本身是称为 PANEL_BUTTON 的面板项。我们将一个子例程或“回调”例程与一个按钮关联,以便在用户单击该按钮时调用该例程。回调例程将操作文本子窗口。sample.c 程序的第二个版本如 列表 2 所示。

让我们从 main 内部的新代码开始。我们在框架内部创建了一个面板,位于左上角 (x=0, y=0),向右边缘延伸,高度为 30 像素且无边框。

接下来,我们向面板(而不是框架)添加了两个按钮,每个按钮都有不同的按钮标签和不同的回调例程。对于此示例,XView 处理在面板内定位按钮的繁琐工作。如果我们愿意,我们可以使用 XV_X 和 XV_Y 属性在控制面板内定位按钮。

Programming with XView

图 1. 窗口中的层次结构

请注意,层次结构(参见图 1)正在形成。框架是面板和文本子窗口的父组件。面板是两个按钮的父组件。当我们调整框架大小时,其子组件也随之调整大小。用户界面可能会变得非常复杂(即,复杂),但由于框架、面板和其他组件之间形成的关系,仍然可以保持可管理性。我们的回调例程由 XView 内部深处的其他例程调用,并传递生成此调用的组件和事件(在本例中,是按钮和鼠标按钮弹起事件)。

对于 insert string 回调例程,我们使用文本子窗口的全局句柄,并调用一个辅助例程将文字文本插入到文本窗格中。对于 clear_window 回调例程,我们使用另一个辅助函数来重置文本子窗口,这将擦除其窗格中的所有文本。虽然我们使用 xv_set 和 xv_get 来操作 XView 组件的属性,但某些组件有一组不错的辅助函数,可以使我们的工作更轻松。文本子窗口就是这样一个组件。

虽然这个示例程序没有给您带来一个惊天动地的应用程序,但它确实向您展示了 XView 的核心功能

  • 属性-值对

  • 以 null 结尾的列表

  • 用于设置和事件处理的 xv_init 和 xv_main_loop

  • 用于组件属性的 xv_create、xv_set、xv_get

  • 用于事件处理的回调函数

本文演示了 XView 的简洁性、优雅性和美观性。也许它会启发您进一步研究。

XView 组件

资源

Mike Hall 是 BALR Corporation 的高级顾问,BALR Corporation 是一家芝加哥地区的计算机咨询公司。他最近的任务是在 Suns 上使用 XView 和 display PostScript。可以通过 mghall@balr.com 联系他。

加载 Disqus 评论