백엔드 개발 파이썬 튜토리얼 在Python中封装GObject模块进行图形化程序编程的教程

在Python中封装GObject模块进行图形化程序编程的教程

Jun 10, 2016 pm 03:15 PM
python

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 的空文件,然后创建一个空的 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 模块的初始覆盖文件。
清单 1. trayicon.override

%%
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:
清单 2. 初始 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:
清单 3. TrayIcon 模块代码

#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:
清单 4. 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
로그인 후 복사

共享对象是根据生成的代码、我们刚才编写的模块代码以及 EggTrayIcon 的实现构造的。隐式规则根据我们创建的 .c 文件构建 .o 文件。

  $(CC) $(LDFLAGS) -shared $^ -o $@
로그인 후 복사

这里我们构建最终的共享库。

现在运行 make trayicon.so 应该会根据定义生成 C 代码,编译三个 C 文件, 最后将它们全都链接在一起。做得不错 — 我们已经构建了第一个本机 Python 模块。 如果它没有编译和链接,请仔细检查这些阶段,并确保早先没有出现会引起稍后出错的警告。

既然我们有了 trayicon.so,就可以在 Python 程序中尝试并使用它。 开始时最好装入它,然后列出其成员。在 shell 中运行 python 以打开交互式解释器,然后输入以下命令。
清单 5. TrayIcon 的交互式测试

$ python
Python 2.2.2 (#1, Jan 18 2003, 10:18:59)
[GCC 3.2.2 20030109 (Debian prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pygtk
>>> pygtk.require("2.0")
>>> import trayicon
>>> dir (trayicon)
['TrayIcon', '__doc__', '__file__', '__name__']

로그인 후 복사

希望从 dir 产生的结果与这里相同。现在我们准备开始一个更大的示例!
清单 6. Hello 示例

#! /usr/bin/python
import pygtk
pygtk.require("2.0")
import gtk
import trayicon                
t = trayicon.TrayIcon("MyFirstTrayIcon")   
t.add(gtk.Label("Hello"))           
t.show_all()
gtk.main()

로그인 후 복사

逐行细化它:

  #! /usr/bin/python
  import pygtk
  pygtk.require("2.0")
  import gtk
  import trayicon
로그인 후 복사

这里,我们首先请求和导入 GTK+ 绑定,然后导入新模块。

  t = trayicon.TrayIcon("MyFirstTrayIcon")
로그인 후 복사

现在创建 trayicon.TrayIcon 的实例。注:构造函数带有字符串参数 — 图标名称。

  t.add(gtk.Label("Hello"))
로그인 후 복사

TrayIcon 元素是 GTK+ 容器,所以您可以将任何东西添加到其中。 这里,我添加一个标签窗口小部件。

  t.show_all()
  gtk.main()
로그인 후 복사

这里,我将窗口小部件设置为可视的,然后启动 GTK+ 主事件循环。

现在,如果您还未这样做,则将 Notification Area applet 添加到 GNOME 面板(在该面板上单击鼠标右键,然后选择“Add to Panel”-> Utility -> Notification Area)。 运行该测试程序应该会在栏中显示“Hello”。很酷,不是吗?

2015414154123688.gif (258×24)

通知区还允许我们做什么?好,程序可以告诉通知区显示消息。 该消息的实际显示方式是特定于实现的;目前,GNOME 通知区显示工具提示。 我们可以通过调用 send_message() 函数发送消息。快速查看 API 可以得知它希望有超时和消息, 所以它应该如下工作:

...
t = trayicon.TrayIcon("test")
...
t.send_message(1000, "My First Message")

로그인 후 복사

但并不是那样。C 原型是 send_message(int timeout, char* message, int length) , 所以 Python API 还需要字符指针和长度。这确实起作用:

...
t = trayicon.TrayIcon("test")
...
message = "My First Message"
t.send_message(1000, message, len(message))

로그인 후 복사

然而,这有点儿难看。这就是 Python;编程应该简单。 如果我们坚持沿着这条路线,那么将以 C 告终,但是没有分号。 幸运的是,在使用 gnome-python 代码生成器时,可以手工封装各个方法。

调优界面

到目前为止,我们已经有了 send_message(int timeout, char *message, int length) 函数。 如果 EggTrayIcon 的 Python API 允许我们调用 send_message(timeout, message) ,那会更好。幸运的是,这并不太难。

完成这一步将再次涉及编辑 trayicon.override。这正是文件名的意义所在:该文件主要包含手工覆盖的包装器函数。 比起演示一个示例并逐步说明其内容来,说明这些函数的工作原理要难得多,所以下面是手工封装的 send_message 代码。
清单 7. 手工覆盖

override egg_tray_icon_send_message kwargs 
static PyObject*
_wrap_egg_tray_icon_send_message(PyGObject *self,
                 PyObject *args, PyObject *kwargs) 
{
  static char *kwlist[] = {"timeout", "message", NULL}; 
  int timeout, len, ret;
  char *message;
  if (!PyArg_ParseTupleAndKeywords(args, kwargs,  
                   "is#:TrayIcon.send_message", kwlist,
                   &timeout, &message, &len))
    return NULL;
  ret = egg_tray_icon_send_message(EGG_TRAY_ICON(self->obj),
                   timeout, message, len);
  return PyInt_FromLong(ret); 
}

로그인 후 복사

为了清晰起见,我们再次将该清单逐行细化:

  override egg_tray_icon_send_message kwargs
로그인 후 복사

该行告诉代码生成器我们将提供 egg_tray_icon_send_message 的手工定义,它本身应该不会生成一个定义。

  static PyObject*
  _wrap_egg_tray_icon_send_message(PyGObject *self,
  PyObject *args, PyObject *kwargs)
로그인 후 복사

这是 Python-to-C 桥的原型。它由正在对其调用方法的 GObject 的指针、参数数组和关键字参数数组组成。 返回值始终是 PyObject* ,因为 Python 中的所有值都是对象(甚至整数)。

  {
  static char *kwlist[] = {"timeout", "message", NULL};
  int timeout, len, ret;
  char *message;
로그인 후 복사

该数组定义该函数接受的关键字参数的名称。 提供使用关键字参数的能力不是必需的,但它可以使带有许多参数的代码变得清楚许多,而且不需要大量的额外工作。

  if (!PyArg_ParseTupleAndKeywords(args, kwargs,
  "is#:TrayIcon.send_message", kwlist,
  &timeout, &message, &len))
  return NULL;
로그인 후 복사

这个复杂的函数调用执行参数解析。我们向它提供所知道的关键字参数以及所有给定参数的列表, 它将设置最终参数指向的值。那个看上去费解的字符串声明了所需要的变量类型,我们稍后将说明它。

  ret = egg_tray_icon_send_message(EGG_TRAY_ICON(self->obj),
  timeout, message, len);
  return PyInt_FromLong(ret);
  }
로그인 후 복사

这里,我们实际上调用 egg_tray_icon_send_message ,然后将返回的 int 转换成 PyObject 。

起先这看上去有点可怕,但它最初是从 trayicon.c 中的生成代码复制来的。 在大多数情况下,如果您只想调优所需要的参数,那么这是完全有可能的。 只要从生成的 C 中复制并粘贴相关函数,添加有魔力的覆盖行并编辑该代码, 直到它如您所愿。

最重要的更改是修改所需要的参数。 PyArg_ParseTupleAndKeywords 函数中看上去费解的字符串定义了所需要的参数。 最初,它是 isi:TrayIcon.send_message ;这意味着参数依次是 int 、 char* (s 表示字符串)和 int ; 而且如果抛出一个异常,则该函数称作 TrayIcon.send_message 。 我们不想必须在 Python 代码中指定字符串长度,所以将 isi 更改为 is# 。使用 s# 来代替 s 意味着 PyArg_ParseTupleAndKeywords 将自动计算字符串长度并为我们设置另一个变量 — 这正是我们想要的。

要使用新的包装器,只需重新构建共享对象并将测试程序中的 send_message 调用更改成:

t.send_message(1000, message)

로그인 후 복사

如果每件事情都照常进行,那么这个修改后的示例应该有相同的行为,但具有更清晰的代码。

结束游戏

我们采用了小型的但有用的 C GObject,封装它,这样就可以在 Python 中使用它, 甚至可以对包装器进行度身定做以符合我们的需要。这里的技术可以多次应用于不同对象, 允许您使用在 Python 中找到的任何 GObject。

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

PHP와 Python : 다른 패러다임이 설명되었습니다 PHP와 Python : 다른 패러다임이 설명되었습니다 Apr 18, 2025 am 12:26 AM

PHP는 주로 절차 적 프로그래밍이지만 객체 지향 프로그래밍 (OOP)도 지원합니다. Python은 OOP, 기능 및 절차 프로그래밍을 포함한 다양한 패러다임을 지원합니다. PHP는 웹 개발에 적합하며 Python은 데이터 분석 및 기계 학습과 같은 다양한 응용 프로그램에 적합합니다.

PHP와 Python 중에서 선택 : 가이드 PHP와 Python 중에서 선택 : 가이드 Apr 18, 2025 am 12:24 AM

PHP는 웹 개발 및 빠른 프로토 타이핑에 적합하며 Python은 데이터 과학 및 기계 학습에 적합합니다. 1.PHP는 간단한 구문과 함께 동적 웹 개발에 사용되며 빠른 개발에 적합합니다. 2. Python은 간결한 구문을 가지고 있으며 여러 분야에 적합하며 강력한 라이브러리 생태계가 있습니다.

Python에서 비주얼 스튜디오 코드를 사용할 수 있습니다 Python에서 비주얼 스튜디오 코드를 사용할 수 있습니다 Apr 15, 2025 pm 08:18 PM

VS 코드는 파이썬을 작성하는 데 사용될 수 있으며 파이썬 애플리케이션을 개발하기에 이상적인 도구가되는 많은 기능을 제공합니다. 사용자는 다음을 수행 할 수 있습니다. Python 확장 기능을 설치하여 코드 완료, 구문 강조 및 디버깅과 같은 기능을 얻습니다. 디버거를 사용하여 코드를 단계별로 추적하고 오류를 찾아 수정하십시오. 버전 제어를 위해 git을 통합합니다. 코드 서식 도구를 사용하여 코드 일관성을 유지하십시오. 라인 도구를 사용하여 잠재적 인 문제를 미리 발견하십시오.

Windows 8에서 코드를 실행할 수 있습니다 Windows 8에서 코드를 실행할 수 있습니다 Apr 15, 2025 pm 07:24 PM

VS 코드는 Windows 8에서 실행될 수 있지만 경험은 크지 않을 수 있습니다. 먼저 시스템이 최신 패치로 업데이트되었는지 확인한 다음 시스템 아키텍처와 일치하는 VS 코드 설치 패키지를 다운로드하여 프롬프트대로 설치하십시오. 설치 후 일부 확장은 Windows 8과 호환되지 않을 수 있으며 대체 확장을 찾거나 가상 시스템에서 새로운 Windows 시스템을 사용해야합니다. 필요한 연장을 설치하여 제대로 작동하는지 확인하십시오. Windows 8에서는 VS 코드가 가능하지만 더 나은 개발 경험과 보안을 위해 새로운 Windows 시스템으로 업그레이드하는 것이 좋습니다.

Python vs. JavaScript : 학습 곡선 및 사용 편의성 Python vs. JavaScript : 학습 곡선 및 사용 편의성 Apr 16, 2025 am 12:12 AM

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

PHP와 Python : 그들의 역사에 깊은 다이빙 PHP와 Python : 그들의 역사에 깊은 다이빙 Apr 18, 2025 am 12:25 AM

PHP는 1994 년에 시작되었으며 Rasmuslerdorf에 의해 개발되었습니다. 원래 웹 사이트 방문자를 추적하는 데 사용되었으며 점차 서버 측 스크립팅 언어로 진화했으며 웹 개발에 널리 사용되었습니다. Python은 1980 년대 후반 Guidovan Rossum에 의해 개발되었으며 1991 년에 처음 출시되었습니다. 코드 가독성과 단순성을 강조하며 과학 컴퓨팅, 데이터 분석 및 기타 분야에 적합합니다.

VScode 확장자가 악의적입니까? VScode 확장자가 악의적입니까? Apr 15, 2025 pm 07:57 PM

VS 코드 확장은 악의적 인 코드 숨기기, 취약성 악용 및 합법적 인 확장으로 자위하는 등 악성 위험을 초래합니다. 악의적 인 확장을 식별하는 방법에는 게시자 확인, 주석 읽기, 코드 확인 및주의해서 설치가 포함됩니다. 보안 조치에는 보안 인식, 좋은 습관, 정기적 인 업데이트 및 바이러스 백신 소프트웨어도 포함됩니다.

터미널 VSCODE에서 프로그램을 실행하는 방법 터미널 VSCODE에서 프로그램을 실행하는 방법 Apr 15, 2025 pm 06:42 PM

vs 코드에서는 다음 단계를 통해 터미널에서 프로그램을 실행할 수 있습니다. 코드를 준비하고 통합 터미널을 열어 코드 디렉토리가 터미널 작업 디렉토리와 일치하는지 확인하십시오. 프로그래밍 언어 (예 : Python의 Python Your_file_name.py)에 따라 실행 명령을 선택하여 성공적으로 실행되는지 여부를 확인하고 오류를 해결하십시오. 디버거를 사용하여 디버깅 효율을 향상시킵니다.

See all articles