在Python中封装GObject模块进行图形化程序编程的教程
|
Python 是用于编码图形界面的极佳语言。由于可以迅速地编写工作代码并且不需要费时的编译周期, 所以可以立即使界面启动和运行起来,并且不久便可使用这些界面。 将这一点与 Python 易于链接本机库的能力结合起来,就可以形成一个出色的环境。 gnome-python 是为 Python 封装 GNOME 及其相关库的软件包。 这使您能够用 Python 编写外观与核心 GNOME 应用程序完全相同的应用程序,而所花的时间只是用 C 编写该应用程序所花的一部分。 然而,不用 C 进行编程会有一个缺点。大多数 GNOME 都是用 C 编写的,对于要在 Python 中使用的窗口小部件,必须将它们封装。 对于知道封装过程如何工作的人来说,这是一个快速任务,但它不是自动的, 除非窗口小部件属于核心 GNOME 库或者至少非常有用,否则将不会对它们进行封装。C 程序员可能必须编写更复杂的代码,但它们确实先做了这一步! 但并不一定是那样!虽然从传统上讲封装窗口小部件过程这一技术只有极少数人才知道,但它并不真的那么难。 如果您在发现新的窗口小部件时可以将它们封装,那么您就可以立刻在 Python 程序中使用它们。 本文将描述如何封装用 C 编码的 GObject(所有 GTK+ 窗口小部件和许多相关对象的最终基类), 以便可以从 Python 代码使用它。假设您的机器上安装了 gnome-python V1.99.x(如果没有安装, 请参阅 参考资料以获取链接)。如果您正在使用软件包,请确保安装了该开发软件包。 另外,还必须安装 Python 2.2 及其头文件。 假设您了解 Make、Python、GTK+ 2 和一些 C 方面的知识。 为了演示该过程,我将封装 EggTrayIcon ,它是用于在通知区中抽象表示图标的 GTK+ 窗口小部件。 该库在 GNOME CVS 中,位于 libegg 模块。在本文的结尾,我们将有一个名为 trayicon 的本机 Python 模块,它包含一个 TrayIcon 对象。 开始时,获得 eggtrayicon.c 和 eggtrayicon.h(其链接在本文结尾的 参考资料一节中),然后将它们放入新目录中。 应该在 automake 环境中构建该源文件(但我们将不在这种环境中), 所以或者除去这些文件中的 #include <config.h> ,或者创建一个名为 config.h 的空文件,然后创建一个空的 makefile;接下来,我们将填充它。 该对象封装过程的第一步是创建 trayicon.defs,该文件为该对象指定 API。 定义文件是用一种类 Scheme 的语言编写的,虽然对于小型界面来说它们很容易生成, 但对于大型界面或初学者来说编写它们会很吃力。 gnome-python 与名为 h2def 的工具一起提供。该工具将解析头文件并生成粗略的定义文件。 注:因为它实际上并没有解析 C 代码,而只是使用正则表达式, 所以它的确要求传统格式化的 GObject,并且不能正确解析奇特格式化的 C 代码。 要生成初始定义文件,我们如下调用 h2def : python /usr/share/pygtk/2.0/codegen/h2def.py eggtrayicon.h > trayicon.defs 注:如果没有将 h2def.py 安装在 /usr 下,则必须更改该路径以指向它所在的地方。 如果我们现在查看已生成的定义文件,它应该具有某些意义。 该文件中含有类 EggTrayIcon 的定义、构造函数以及方法 send_message 和 cancel_message 。 该文件没有任何明显错误,我们不想除去任何方法或字段,所以我们不需编辑它。 注:该文件不是特定于 Python 的,其它语言绑定也可以使用它。 生成包装器 既然我们有了界面定义,那么就可以生成 Python 包装器的代码块。这包括生成一个覆盖文件。 覆盖文件告诉代码生成器要包括哪些头文件、模块名将是什么等等。 通过使用 %% 将覆盖文件分成多个节(以 lex/yacc 样式)。 这些节定义要包括哪些头文件、模块名、要包括哪些 Python 模块、要忽略哪些函数以及最后所有手工封装的函数。 下面是 trayicon 模块的初始覆盖文件。 %% headers #include <Python.h> #include "pygobject.h" #include "eggtrayicon.h" %% modulename trayicon %% import gtk.Plug as PyGtkPlug_Type %% ignore-glob *_get_type %% 让我们再次更详细地检查该代码: headers #include <Python.h> #include "pygobject.h" #include "eggtrayicon.h" 这些是在构建包装器时要包括的头文件。 始终必需包括 Python.h 和 pygobject.h,当我们封装 eggtrayicon.h 时,我们也必需包括它们。 modulename trayicon modulename 规范声明包装器将在什么模块中。 import gtk.Plug as PyGtkPlug_Type 这些是用于包装器的 Python 导入。请注意命名约定;对于要编译的模块,必须遵守它。 通常,导入对象的超类就足够了。例如,如果对象直接从 GObject 继承,则使用: import gobject.GObject as PyGObject_Type ignore-glob *_get_type 这是一个要忽略的函数名的 glob 模式(shell 样式的正则表达式)。Python 替我们处理了类型代码,因此我们忽略 *_get_type 函数;否则,将对它们进行封装。 既然我们构造了覆盖文件,那么就可以使用它来生成包装器。 gnome-python 绑定为生成包装器提供了一种神奇的工具, 我们可以随意使用它。 将下列内容添加到 makefile: 再次详细说明:
DEFS='pkg-config --variable=defsdir pygtk-2.0' DEFS 是包含 Python GTK+ 绑定定义文件的路径。 trayicon.c: trayicon.defs trayicon.override 生成的 C 代码取决于定义文件和覆盖文件。 pygtk-codegen-2.0 --prefix trayicon 这里调用 gnome-python 代码生成器。 prefix 参数被用作在已生成的代码内部的变量名的前缀。 您可以随意命名该参数,但使用模块名的话可使符号名保持一致。 --register $(DEFS)/gdk-types.defs --register $(DEFS)/gtk-types.defs 模块使用 GLib 和 GTK+ 中的类型,所以我们还必须告诉代码生成器装入这些类型。 --override trayicon.override 该参数将我们创建的覆盖文件传递给代码生成器。 trayicon.defs > $@ 这里,代码生成器的最后一个选项是定义文件本身。 代码生成器在标准输出上进行输出,所以我们将它重定向到目标 trayicon.c。 如果我们现在运行 make trayicon.c ,然后查看已生成的文件, 那么我们会看到 C 代码包装 EggTrayIcon 中的每个函数。不必担心警告 No ArgType for GdkScreen*― 这是正常的。 正如您所看到的那样,封装代码看上去复杂,所以我们感谢代码生成器为我们编写的每一行。 稍后,我们将学习当想要调优封装时如何手工封装各个方法,而我们自己不必编写所有包装器。 创建模块 既然已经创建了包装器的代码块,那么就需要一个启动它的方法。 这涉及创建 trayiconmodule.c,该文件可被视为 Python 模块的 main() 函数。 该文件是样板文件代码(与覆盖文件相似),我们对它稍作修改。下面是我们将使用的 trayiconmodule.c:
#include <pygobject.h>
void trayicon_register_classes (PyObject *d);
extern PyMethodDef trayicon_functions[];
DL_EXPORT(void)
inittrayicon(void)
{
PyObject *m,*d;
init_pygobject ();
m = Py_InitModule ("trayicon",trayicon_functions);
d = PyModule_GetDict (m);
trayicon_register_classes (d);
if (PyErr_Occurred ()) {
Py_FatalError ("can't initialise module trayicon");
}
}
这里需要说明一下一些细微的区别, 因为有多个使用单词 trayicon 的源代码。函数 inittrayicon 的名称和初始化模块的名称是 Python 模块的真实名称,因此是最终共享对象的名称。 数组 trayicon_functions 和函数 trayicon_register_classes 是根据代码生成器的 --prefix 参数命名的。正如前面所提到的那样,最好使这些名称保持一致,以便编码该文件不会变得很混乱。 尽管名称源可能存在混淆,但该 C 代码非常简单。 它初始化 GObject 和 trayicon 模块,然后向 Python 注册这些类。 现在我们有了所有代码块,就可以生成共享对象了。将以下内容添加到 makefile: CFLAGS = 'pkg-config --cflags gtk+-2.0 pygtk-2.0' -I/usr/include/python2.2/ -I. LDFLAGS = 'pkg-config --libs gtk+-2.0 pygtk-2.0' trayicon.so: trayicon.o eggtrayicon.o trayiconmodule.o $(CC) $(LDFLAGS) -shared $^ -o $@ 让我们再次逐行仔细检查: CFLAGS = 'pkg-config --cflags gtk+-2.0 pygtk-2.0' -I/usr/include/python2.2/ -I. 该行定义 C 编译标志。我们使用 pkg-config 来获取 GTK+ 和 PyGTK 的 include 路径。 LDFLAGS = 'pkg-config --libs gtk+-2.0 pygtk-2.0' 该行定义链接程序标志。再次使用 pkg-config 来获取正确的库路径。 trayicon.so: trayicon.o eggtrayicon.o trayiconmodule.o (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
