Kode KDE 恳请您,可以吗?
只需一点编程经验,阅读完本文后,您将拥有构建 Linux 桌面应用程序所需的一切。
作者:Jason Mott
构建 Linux 桌面应用程序有很多工具包可供选择。有人说这是 Linux 的缺点;也有人说这是它最大的特点。我将站在中间立场,认为选择是好的,只要您选择适合您需求的工具。Linux 上大多数图形用户界面 (GUI) 都基于 X,这是一种客户端/服务器架构,允许联网计算机共享 GUI 应用程序。使用 X,应用程序是客户端,它将其图形输出发送到 X 服务器。X 服务器代表其本地硬件(或有时是虚拟硬件,但本文我不会深入探讨)接受应用程序的输出。在大多数情况下,X 服务器和 X 客户端在同一台机器上,但仍然使用客户端/服务器架构。
用于构建 X 客户端的基础级别工具包称为 Xlib。Xlib 本身过于底层且难以使用,无法从头开始构建应用程序。因此,许多工具包都构建在 Xlib 之上,以简化为 X 编写 GUI 应用程序的过程。随后,当使用其中一个高级工具包编写 GUI 应用程序时,您甚至不会意识到它是一个网络应用程序(它正在将其图形输出发送到服务器)。
在 Xlib 之上分层的两个最流行的开源工具包是 Qt 和 GTK+,KDE 和 GNOME 分别基于它们构建。Motif 是另一个流行的工具包(不是开源的,但有一个名为 Lesstif 的开源克隆)。图 1 显示了这些工具包(以及更多)及其相互关系的图表。在图表中越靠下,API 的级别就越低。我出于多种原因更喜欢 KDE/Qt,但主要是因为它专注于良好的用户界面和简洁且设计良好的 API。
实际上,我为本文从头开始构建了一个应用程序(一个计算器),以展示它有多么快速和容易。要跟随本文进行操作,您需要一些工具——最重要的是,KDevelop。我使用了在 KDE 2.2.2 上运行的 2.0.2 版本。当使用 KDevelop 的设置向导时,您将被告知您缺少哪些依赖项。访问 KDevelop 网站 (www.kdevelop.org) 或查看您的发行版附带的软件,并安装 KDevelop。如果您的发行版包含 KDE,那么您将拥有 KDevelop。
大多数关于应用程序开发的教程都试图与 IDE 无关。我决定不这样做,原因有几个:KDevelop 是免费的,并且随 KDE 一起提供;KDevelop 使已经很简单的 API 变得更加容易,并且 KDevelop 的向导可以帮助开发人员遵循 KDE 用户界面标准。对于那些不喜欢处理 Makefile 或创建 configure 文件(甚至处理更简单的 automake 和 autoconf)的人来说,KDevelop 将为您处理这些事情。对于喜欢摆弄 Makefile 的极客来说,KDevelop 允许您调整它们。实际上,您的 KDevelop 应用程序已准备好使用传统的 ./configure、make、make install 进行构建。换句话说,您可以随时摆脱 KDevelop 的束缚。
首次启动 KDevelop 时,它将运行一个设置向导。向导最重要的部分是它检查依赖项(图 2)的时候。花时间查看此输出;如果列出了失败项,请帮自己一个忙,尝试找到所需的库。最简单的方法是使用 www.rpmfind.com(如果您的发行版是基于 RPM 的)。对于每个失败的库,在 rpmfind 网站上搜索它。从搜索结果中,选择适合您的发行版的 RPM 并安装它。完成此操作后,重新运行 KDevelop 向导(在命令行中键入 kdevelop --setup 或在您的 K 菜单中找到一个名为 KDevelop Setup 的条目)。如果仍然有缺少项,请根据需要重复此操作。

图 2. KDevelop 设置向导
我构建的计算器很简单,只执行基本的算术运算。整个过程大约花了两个小时完成(好吧,三个小时,但我并不着急)。我本打算将其命名为 Kalculator,但已经有一个不知名的应用程序使用了这个名称。所以我选择了 Kalculate。我没有使用或查看 KDE 自带的计算器 KCalc 的任何代码,KCalc 具有比我的更多的数学功能。我一直觉得 KDE 应该有一个基本的计算器,所以我希望看到用户友好的功能添加到 Kalculate 中,而不是更多的数学功能。因此,当您阅读完本文后,您可以成为开源开发的活生生的实验的一部分——加入团队并添加一个功能!如果您说这篇文章推荐了您,您将获得特别优惠 (sourceforge.net/projects/kalculate)。
我们不会从一个新项目开始,而是从互联网的力量开始;我们将使用 Kalculate。要从官方 CVS 服务器获取 Kalculate 的代码,请键入以下命令(假设您具有写入权限,如果没有,请创建一个名为 /usr/local/src 的目录)
cd /usr/local/src cvs -d:pserver:anonymous@cvs.kalculate.sourceforge.net: /cvsroot/kalculate login
如果此命令要求输入密码,请按 Enter 键;不需要密码。
cvs -z3 -d:pserver:anonymous@cvs.kalculate. sourceforge.net:/cvsroot/kalculate co kalculate当然,如果您想自己构建此应用程序,您不会抓取源代码。但是因为我不会在这里进行逐行细分,所以最好获取源代码,然后使用您的新知识来添加功能或构建新应用程序。
这里使用的设计模式称为文档-视图模型。它从三个特定于应用程序的类开始:KalculateApp、KalculateDoc 和 KalculateView。如果您使用 KDevelop 重新开始这个项目,将为您创建这三个类。对于 Kalculate,除了模板中提供的类之外,我没有添加任何其他类。我这样做是有目的的,以便很容易演示设计模式,并展示 KDevelop 让您走了多远。我所要做的就是修改三个类,添加几个图标和 瞧!
文档-视图的基本概要是,业务逻辑进入文档端,而用户界面内容进入视图端。从理论上讲,同一个文档可以有多个视图。在通用意义上,“文档”是“事物”的一个开放会话。当然,这对于像文本编辑器之类的东西来说最容易理解。在这种情况下,文档对象将代表文本文件的所有行为和属性,而视图对象将提供文本到屏幕的显示和用户界面。您甚至会在骨架代码中注意到,保存、打印、打开和关闭例程都为您存根了。显然,文本编辑器隐喻是此模型的基础。
然而,正如 Kalculate 的情况一样,这种隐喻并不总是有效。计算器实际上没有它代表的文件;它有一组它代表的特定功能。因此,尽管 KalculateDoc 类将提供我们的业务逻辑,但我们不需要打开、关闭、保存和打印功能。目前,在 Kalculate 代码中,我注释掉了(KDevelop 提供的)我不需要的库存代码,而不是删除它。这样,如果需要,我们仍然有存根。
对于计算器,我们在业务逻辑方面(KalculateDoc)需要的是能够输入数字,为这些数字分配操作并获得结果数字(当然,在内部它实际上需要执行操作)。在用户界面方面,我们需要用于输入数字和输入操作的按钮,以及数字的显示。假设您将 cvs 检出放入 /usr/local/src,您将拥有一个 /usr/local/src/kalculate 目录。键入以下内容
cd /usr/local/src/kalculate kdevelop kalculate.kdevprj &
这将打开项目。KDevelop 将其项目信息存储到一个以项目名称命名的文件中,并以 .kdevprj 结尾。根据您的首选项设置方式,您应该看到类似于图 3 的内容。如果您在左侧看不到项目树,请确保选择了视图-->树工具视图-->文件。您将看到项目文件结构单击到 kalculate 目录中(是的,这是一个 kalculate 目录下的 kalculate 目录,不要揉眼睛)。这里是所有源文件。现在特别感兴趣的是 kalculatedoc.cpp 和 kalculatedoc.h 文件。双击它们。这两个文件是我们计算器的核心——KalculateDoc 类处理所有处理。它是一台虚拟机,需要有人将控件连接到它。如果您查看 kalculatedoc.h,您会注意到类声明中有些非常奇怪的地方——似乎存在不正确的语法。这使我们进入了 slots 和 signals 的世界。
在事件驱动的应用程序(例如桌面应用程序)中,需要构建一个子系统,以便在事件发生时通知组件。事件可以是某种类型的用户交互(移动鼠标指针、按下鼠标按钮、按下键等)。事件也可能是其他软件组件宣布某些条件(例如,时间、文件系统已满等)。GUI 应用程序中,尤其是 Kalculate 中,一个流行的事件是按钮小部件已被按下。在 KDE 领域,事件称为信号 (signals),而处理事件的东西称为槽 (slots)。作为开发人员,您可以创建信号和槽,并且您可以控制哪些槽连接到哪些信号。您还可以将您的槽连接到库存信号(反之亦然),或将库存信号连接到库存槽。库存是指使用已经定义了槽和/或信号的 KDE 或 Qt 库类。
KDE(以及 Qt)之所以能够使用不正确的语法,是因为它使用了标准的 C++ 预处理器 #defines,它将 signals: 替换为 protected:,将 slots 和 emit 替换为空。moc(在预处理器之前运行)需要额外的语法。元对象编译器 (moc) 是 Qt 库附带的一个程序,它在您的 QObject 头文件上运行,以便为您的类创建额外的方法,使它们可以用作 QObject 子类。所有使用槽和信号的对象都必须是 QObject 的子类,并且类定义必须调用 Q_OBJECT 宏(正如您在 kalculatedoc.h 文件中看到的那样)。QObject 超类有一个 connect 方法,这就是您用来连接槽和信号的方法。
要创建信号,请在您的类声明中的 signals: 下声明它们。对于信号,您实际上不必创建后续方法。您所要做的就是在信号名称上调用 emit,任何连接到它的槽都将被调用;moc 实际上为您创建了信号方法。
另一方面,槽必须创建。您在 public slots 或 protected slots 下声明您的槽,然后在您的 .cpp 文件中将它们定义为普通方法。然后您可以随时连接它们。像这样
connect(this, SIGNAL( mySignal() ), this, SLOT( mySlot() ) );
假设您在同一个类中定义了一个名为 mySignal() 的信号和一个名为 mySlot() 的槽,则上面对 connect 的调用会将它们绑定在一起,以便任何时候调用 emit mySignal(),mySlot() 都会被调用。如果您想将您的槽连接到某些其他对象中的某些其他信号,那么您的第一个参数将是对象的实例,而您的第二个参数将是带有信号名称在括号内的 SIGNAL() 宏。就这么简单。所有困难的事情(包括在您的头文件上运行 moc)都由 KDevelop 完成。
因此(回到我们的计算器),KalculateDoc 类是一系列槽。每个槽代表一个在计算机器上执行的操作。头文件声明了所有槽,如清单 1 所示。同样,使这些方法特别的唯一原因是它们位于“public slots:”标签下,因此 moc 将创建一些关于它们的元数据。作为槽,您仍然需要像普通方法一样定义这些方法(查看 kalculatedoc.cpp 以查看我对这些槽的定义)。另一方面,信号,您不需要定义;moc 会为您完成。
所以现在我们所需要的只是一个使用这个类的 GUI。输入 KalculateView(我希望您实际上正在打开源代码并查看它)。kalculateview.h 文件定义了我们提供 GUI 的类。在“protected”下,您将看到声明了几个布局管理器、一个 LCD 显示屏和几个按钮。我确实向 KDevelop 的库存模板代码添加了一个文件;它被称为 kalculatesizes.h,以下是其中的内容
#ifndef KALCULATE_SIZES_H #define KALCULATE_SIZES_H #define BUTTON_WIDTH 35 #define BUTTON_HEIGHT 35 #define LAYOUT_SPACING 4 #define MAX_WIDTH (BUTTON_WIDTH * 5) + ((LAYOUT_SPACING *2) * 4) #define MAX_HEIGHT (BUTTON_HEIGHT * 5) + ((LAYOUT_SPACING *2) * 4) #endif // SIZES_H
基本上,它设置了我们计算器的大小。我决定使用不可调整大小的计算器,但我希望可以轻松更改按钮大小。所以我在这个文件中定义了大小。只需编辑此文件并重新编译即可获得具有不同大小按钮的计算器(也许未来的版本可以允许动态调整,但我出于某种原因对此犹豫不决)。
在 KalculateView 中,构造函数(在 kalculateview.cpp 中)是此应用程序开始运行的地方。对 setMaximumSize() 的调用使它不可调整大小。大小策略也有帮助,但只是一个建议。我在这里花一点时间解释一下布局管理器。基本上,每个 GUI 小部件都有设置其几何形状(高度、宽度、相对位置等)的方法。当应用程序首次设置时,以及随后调整大小时,如果您必须编写代码来调整大小或重新定位它,那将非常无趣。并且在初始设置时,如果没有布局管理器,此应用程序中的所有按钮都必须使用硬编码的 x/y 坐标进行定位。当您想要更改计算器的大小时,这可能需要花费数小时的时间。因此,我们没有硬编码几何属性,而是将我们的小部件注册到遵循特定规则的布局管理器,例如,QVBoxLayout,它在垂直列中添加小部件。每次您使用 addWidget() 方法像这样放置一个小部件时
outerLayout->addWidget(output,1);
它会将小部件添加到前一个小部件的正下方。QHBoxLayout 会将小部件添加到前一个小部件的正右侧。第二个参数是所谓的拉伸因子。基本上,拉伸因子决定了这个小部件相对于添加到这个布局管理器的其他小部件将占用多少空间。因此,如果它们都是 1,那么它们的大小都将相同(除非像 setMaximumSize 这样的因素覆盖它)。它取所有拉伸因子的总和并应用一个比率。因此,如果您有两个小部件,第一个的拉伸因子为 1,第二个的拉伸因子为 2,那么第二个将是第一个的两倍大。
真正酷的事情(如 KalculateView 中所示)是您可以将布局管理器添加到布局管理器。这允许您创建非常复杂的布局。继续玩 Kalculate 代码;看看你能创造什么。
因此,要运行此应用程序,请执行以下操作。从“构建”菜单中选择“Autoconf 和 Automake”。然后从“构建”菜单中选择“配置”。当它要求输入参数时,键入 --prefix=[您的 KDE 基础目录]。这将允许您安装应用程序,如果您希望应用程序的图标显示出来,则需要安装应用程序。在我的机器上,它是 Mandrake,KDE 的基础目录是 /usr。您的发行版可能有所不同。然后,从“构建”菜单中选择“执行”,它将编译并运行。您应该看到类似于图 4 的内容。但是,在您安装它之前,左上角的图标可能会丢失。要安装,请以 root 身份键入
cd /usr/local/src/kalculate make install <center>

图 4. Kalculate
我希望我已经为您指明了正确的方向。我几乎没有触及您可以使用 KDE 完成的所有事情的表面,但我已经向您展示了 KDevelop 如何让您快速入门。它几乎为您处理了所有后端工作,并为您提供了一个可以在没有 KDevelop 的情况下在命令行上编译的应用程序(这对于分发您的代码很有好处)。如果您有任何问题,请随时给我发送电子邮件,我鼓励您加入 Kalculate 团队并添加一些功能。

Jason Mott (jmott@users.sourceforge.net) 是一位独立软件顾问,目前在纽约州罗切斯特的 ElementK (www.elementk.com) 工作,帮助构建他们的在线培训网站。他也是一名兼职 Linux 顾问,当他有空闲时间时,他会构建 Linux 桌面应用程序。