KDE 编程初探

作者:David Sweet

K 桌面环境(KDE)的既定目标是为 Linux/UNIX 系统提供一个免费、用户友好的桌面。该项目的参与者首先提供了一个窗口管理器 (kwm/kpanel) 和一个文件管理器 (kfm),并改造了流行的 X 应用程序(例如,Ghostview、xcalc、ezppp),使它们具有基于 Troll Tech 的 Qt 部件集的通用外观和感觉。随着时间的推移,KDE 库(提供 UI 元素和文件管理服务)的功能不断增强,因此开发符合 KDE 规范的应用程序不仅简单,而且极具吸引力。

本文中介绍的程序 khello 应该为您编写自己的 KDE 应用程序或为您喜爱的 UNIX 应用程序提供 K-UI 打下良好的基础。要编译该程序,您需要安装 Qt 1.3 和 KDE。有关详细信息,请参阅 http://www.kde.org/beta1.html。尽管 KDE 刚刚以 beta 形式发布,但它非常稳定且可用。事实上,自 beta 发布之前(alpha 版本和频繁的开发“快照”已经可用一段时间了),它一直是我的家用电脑上的主要桌面。

像之前的许多人一样,我选择展示一个向用户说“Hello World!”的程序。然而,KDE 应用程序的基本要素都已呈现:菜单栏、工具栏和“关于”框,以及 KApplication 和 KTopLevelWidget 提供的功能。UI 组件由 libkdeui 中的类提供;KApplication 属于 libkdecore。

A First Look at KDE Programming

KApplication 是 KDE 应用程序派生自的基类。它处理简单的会话管理、对应用程序图标、帮助文件以及配置和区域设置信息的访问。KApplication 构造函数接受 argcargv 作为参数,并剥离 X11 或 KApplication 使用的任何内容,并更新 argc,以便您可以继续处理程序的选项。宏 kapp 定义为 KApplication::getApplication()。这会返回指向 KApplication 对象的指针。在创建 KApplication 后,您可以在程序中的任何位置使用 kapp。因此,当然,您只能创建一个 KApplication 对象。GUI 通过 app-exec() 启动,并在调用 app->quit() 时返回。请注意,您的 KApplication 实例无需被告知您的 KTopLevelWidget。在我们的例子中,这意味着从 KTopLevelWidget 派生的 KHelloTW。只能有一个 KTopLevelWidget,它会告知 KApplication 自身。

用户界面的基础由 KTopLevelWidget 提供。它将管理菜单栏、多个工具栏和状态栏,您无需调整这些对象的大小或位置;只需创建它们并填充适当的信息即可。(KTopLevelWidget 也处理一些会话管理,但这里不会详细讨论此主题。)您应该从 KTopLevelWidget 派生一个类,就像 KHelloTW 一样,并在调用 show() 之前设置 UI(例如,在构造函数中)。这样,您的窗口就不会在子部件被创建和/或重新排列时出现并“闪烁”。您必须在调用 app->exec() 之前为您的 KTopLevelWidget 调用 show(),因为它不会自动显示。

让我们看一下 khellotw.cpp (列表 1),以了解如何在 KDE 和 Qt 中工作。首先,我们创建文件菜单。我们将“file”声明为 QPopupMenu 类型的对象的指针,并使用“new”创建了该对象,以便文件菜单在 KHelloTW 的生命周期内(在本例中,也是程序的生命周期)可用。insertItem 方法将一个项目放置在菜单上。在本例中,我们只有“Quit”。参数 &Quit 中的 & 告诉 Qt 在字母 Q 下划线,并且当此菜单可见时,允许用户通过按 Q 选择“Quit”。最后一个参数 kkeys->quit() 表示用户可以随时按下 KStdAccel::quit() (ctrl-Q) 中定义的组合键,以退出程序(这称为“加速键”)。KStdAccel 类包含各种标准的 KDE 加速键。我们在创建菜单时使用这些定义,以与 KDE 的外观和感觉保持一致。其他两个参数告诉 Qt 在选择“Quit”时调用哪个方法 (slotQuit()) 以及在哪个类的实例中调用该方法。这种从 GUI 获取消息的系统称为“信号与槽”。如果我们使用 Qt 预编译器(称为 moc,即 Meta-Object Compiler),我们可以像使用 C++ 的自然组成部分一样使用这些信号与槽。

使用 moc,我们获得了三个新的 C++ 关键字:signalslotemit。在 khellowtw.h 中,“public slots:”标题下声明了几个方法。这些方法可以直接调用,就像普通方法一样,但也可以连接到信号。每当发生任何 GUI 事件时,都会发出信号。此时调用所有连接到该信号的槽,甚至可以使用参数调用,以便可以在类之间传递信息。(有关如何使用信号和槽以及 emit 定义的详细信息,请参阅 Qt 文档。)

如果我们查看 khellotw.cpp 中的 toolbar->insertButton 行,该行将 QPushButton 放置在工具栏上,我们会看到

SIGNAL ((released()), this, SLOT (slotHello()))

这告诉 KToolBar 将信号 released()(在按下按钮后释放按钮时由 QPushButton 发出)连接到槽 slotHello(),该槽在我们的窗口中显示短语“Hello world!”。请注意,我们选择了 QPushButton 信号 released() 而不是 pressed(),因为用户期望在释放按钮时而不是在按住按钮时发生操作。您可以尝试更改此设置以查看界面感觉上的差异。

moc 预编译器从您的头文件生成一些 C++ 代码,并创建一个 .moc 文件。此 .moc 文件应在实现该类的文件之一中包含一次且仅包含一次。请注意,khellotw.cpp 包含 khellotw.moc,但 main.cpp (列表 2) 包含 khellotw.h (列表 3)

为了使 KHello 具有 KDE 应用程序的外观,我们添加了一个 KToolBar 并使用了 KDE 提供的图标之一作为按钮。为了构建按钮图标的路径,我们使用了 kapp->kdedir() 而不是硬编码路径,因为用户可能会将 KDE 安装在文件系统中的不同位置。对于路径的其余部分,请参考 KDE 文件系统标准(或 KFSSTD,网址为 http://www.kde.org/fsstnd.html)。我们的菜单栏上还有一个帮助菜单。KApplication 在 kapp->getHelpMenu() 中为您提供了一个基本帮助菜单。此菜单包括“关于 KDE...”和可选的“关于 Qt...”条目,这些条目告诉用户有关底层软件的信息,以及一个“帮助”条目,该条目将启动 KDE 帮助查看器 (kdehelp),并带有参数

kdedir()+ "/share/doc/default/khello"

这指的是默认的 KDE 帮助文件/目录。如果您想看到它的实际效果,只需创建该目录,在其中放置一个名为 khello.html 的 HTML 文件,然后从 khello 帮助菜单中选择“帮助”。当以这种方式调用帮助时,KApplication 使用传递给其构造函数的字符串作为应用程序的名称(在本例中为 khello)。因此,无需告诉 KDE 您的帮助文件在哪里;它由 KFSSTD 确定,并且是 /share/doc/default/appname/appname.html。

列表 4. Makefile

类似地,您可以通过将 appname.xpm 文件放置在 /share/icons/ 中来为您的应用程序提供图标(该图标将显示在任务栏中您的应用程序旁边)。我们在菜单底部添加了一个分隔符和“关于 KHello...”。您的“关于”框应至少显示标题、作者和联系信息(用于错误报告、功能请求和对您工作的总体赞扬)。KHello 的简单“关于”框是一个 KMsgBox。这是一个模态对话框,这意味着它是您的程序中唯一在显示期间响应用户输入的窗口。当用户选择“确定”时,该框消失,函数调用返回,程序继续运行。对于简单的对话框,无需创建 KMsgBox 的实例。方法 KMsgBox::message() 是静态的,可以直接调用,就像在 KHelloTW::slotAbout() 中完成的那样。

通过拖放进行应用程序通信是内聚桌面不可或缺的一部分。如果您的应用程序处理数据文件,则应接受从 kfm(KDE 文件管理器)拖动的 URL 并相应地处理它们。这很容易做到,khello 通过显示任何拖放到其上的 URL 来演示这一点。要接受 URL 拖放事件,请通过创建 KDNDDropZone 对象并将其 dropAction() 信号连接到将处理该事件的槽来声明窗口部件为“拖放区”。调用的 KDNDDropZone 方法 getURLList() 将返回一个 QStrList(一个 Qt 实用程序类,用于管理字符串列表),其中包含在单个拖放事件中拖放的一个或多个 URL。函数 slotDropped() 将“label”的文本设置为列表中的第一个 URL。

有几种方法可以关闭应用程序。用户可以从系统菜单中选择“关闭”(右键单击标题栏会弹出此菜单)或单击关闭按钮(标题栏上的“X”),或者当 X 会话终止时,窗口管理器可能会关闭应用程序。所有这些都会调用 KTopLevelWidget 的 closeEvent() 成员函数。因此,这是您应该提出至关重要的问题“您想保存对 ______ 的更改吗?”的地方。然后调用 kapp->quit(),它告诉您的 KApplication 您已完成,并且 main() 中的 app->exec() 调用返回。为了使您的程序井井有条,如果您向用户提供退出程序的替代方法(例如从“文件”菜单中选择“退出”),则应强制调用 closeEvent()。这样,所有终止前代码都在该位置 (closeEvent())。您可以通过调用 close() 来强制 closeEvent(),它是 KTopWidget 的成员。(事实上,它是 KTopWidget 派生自的 QWidget 的成员。)这是通过 KHelloTW::slotExit() 完成的。

我鼓励您尝试 KHello 并更改代码以了解其他 KDE 类。一个好的起点是 KConfig。此类允许您从存储在 ~/.kde/config/ 中的应用程序特定配置文件中读取和写入。您应该在 closeEvent() 中保存默认程序选项,然后在构造 KTopWidget 时重新读取并设置它们。

KLocale 是 KDE 应用程序的另一个重要类。它通过从文件中读取字符串文字(如“File”、“Help”或“Hello world!”)来帮助您将应用程序翻译成其他语言。KLocale 将根据用户的区域设置选择适当的字符串。您只需提供文本即可。由于 KDE 由世界各地的人们开发和使用,因此翻译您的应用程序是一个好主意;广泛的兴趣使得更容易找到人来帮助进行翻译。

有关 KDE 编程的更多信息,我建议您阅读 http://www.troll.no/qt/tutorial.html 上的 Qt 教程,并访问 http://www.ph.unimelb.edu.au/~ssk/kde/devel/ 上的 KDE 开发者中心。在这里,您将找到有关 KDE 编程的有用提示,以及 KDE 库的文档和新 KDE 应用程序的想法。根据 KDE 项目的精神,请在 KDE 邮件列表中宣布您创建应用程序的意图,以便不会重复工作。您还将了解其他人对使用您提议的应用程序的兴趣程度,并且很可能会收到大量有关程序功能的建议。祝您 KDE 编程顺利。

David Sweet 是马里兰大学三年级的物理学研究生,也是 KDE 项目的参与程序员。他目前正在开发 Ispell 的接口和一个名为 KPlot 的绘图软件包 (http://www.glue.umd.edu/~dsweet/KDE)。可以通过电子邮件 dsweet@chicago.umd.edu 与他联系。

加载 Disqus 评论