在 Python3 通过 ctypes 直接使用 Gtk 编写 GUI

36 views
Skip to first unread message

Jiahua Huang

unread,
Sep 12, 2009, 12:19:45 AM9/12/09
to python-cn
Python3 现在还缺少许多 Python2 里可用的 C 库,如常见的 PyGtk
不过既然 Python2.5 以后就自带了 ctypes ,所以也可以无须传统的 PyGtk 库,
而直接用 ctypes 干 GUI

先看个简单的 Gtk 窗口

teswindow.py

#!/usr/bin/python3

# -*- coding: UTF-8 -*-

import ctypes

gobject = ctypes.CDLL('/usr/lib/libgobject-2.0.so')

gtk = ctypes.CDLL('/usr/lib/libgtk-x11-2.0.so')

gobject.g_type_init ()

gtk.gtk_init(None, None)

win = gtk.gtk_window_new(0)

gtk.gtk_window_set_title(win, ctypes.c_char_p("Gtk TextView"))

gtk.gtk_window_set_default_size(win, 750, 500)

view = gtk.gtk_text_view_new()

gtk.gtk_container_add(win, view)

gtk.gtk_widget_show_all(win)

gtk.gtk_main()

没有使用旧的 PyGtk 库就创建了一个带有文本编辑区的窗口(这代码也可以在 python2.5、2.6 下执行)



再来点额外的库,比如最近很热的 WebKit,
试试
teswebkit.py

#!/usr/bin/python3

# -*- coding: UTF-8 -*-



import ctypes

gobject = ctypes.CDLL('/usr/lib/libgobject-2.0.so')

gthread = ctypes.CDLL('/usr/lib/libgthread-2.0.so')

gtk = ctypes.CDLL('/usr/lib/libgtk-x11-2.0.so')

webkit = ctypes.CDLL('/usr/lib/libwebkit-1.0.so')



gthread.g_thread_init(None)

gobject.g_type_init()

gtk.gtk_init(None, None)



win = gtk.gtk_window_new(0)

gtk.gtk_window_set_title(win, ctypes.c_char_p("Gtk WebKit"))

gtk.gtk_window_set_default_size(win, 750, 500)



view = webkit.webkit_web_view_new ()

webkit.webkit_web_view_open(view, ctypes.c_char_p("http://www.google.cn/")) 



scrolled = gtk.gtk_scrolled_window_new(None, None)

gtk.gtk_container_add(scrolled, view)

gtk.gtk_container_add(win, scrolled)



gtk.gtk_widget_show_all(win)



#gtk.gdk_threads_enter()

gtk.gtk_main()
这是一个嵌入了 WebKit 浏览器的窗口,显示了 谷歌 主页
Screenshot-Gtk WebKit.png


似乎,我们可以不再需要像以前给 PyGtk、PyWebKit 干的那样,特意去用一套很复杂的方法来生成绑定了,
旧的方法不仅费时费力,没绑定好的库还没法去使用。

虽然上边的代码显得非常不 pythonic,不过再用一层纯 python 代码来包装成 python 对象,
也是比创建专门的 C 库要省事得多






Screenshot-Gtk WebKit.png

pong Chong

unread,
Sep 12, 2009, 12:23:51 AM9/12/09
to pyth...@googlegroups.com
thans, very much!

On 9/12/09, Jiahua Huang <jhuang...@gmail.com> wrote:
> Python3 现在还缺少许多 Python2 里可用的 C 库,如常见的 PyGtk不过既然 Python2.5 以后就自带了 ctypes


--
<url>http://www.python8.org</url>引领你进入python的世界

Zoom.Quiet

unread,
Sep 12, 2009, 12:23:52 AM9/12/09
to pyth...@googlegroups.com
2009/9/12 Jiahua Huang <jhuang...@gmail.com>
> 似乎,我们可以不再需要像以前给 PyGtk、PyWebKit 干的那样,特意去用一套很复杂的方法来生成绑定了,
> 旧的方法不仅费时费力,没绑定好的库还没法去使用。
> 虽然上边的代码显得非常不 pythonic,不过再用一层纯 python 代码来包装成 python 对象,

咭,这正是Pythonic 的胶水能力哪....
不错!这样整,C程序员更加习惯迁移到 Py 中哪...

> 也是比创建专门的 C 库要省事得多
>

--
http://zoomquiet.org 人生苦短? Pythonic!
向靠谱,反脑残! Kaopulity,小白退散! [Kaopulity~= Keep all processes usablity!]

Jiahua Huang

unread,
Sep 12, 2009, 12:35:20 AM9/12/09
to pyth...@googlegroups.com
大妈满塞~

那些抱怨 Py3 缺第三方 C 库的得没话说了~

再加上 google unladen-swallow 这个狂快的 VM,
足以在许多地方无缝掉 C 了~

2009/9/12 Zoom.Quiet <zoom....@gmail.com>

Jiahua Huang

unread,
Sep 12, 2009, 1:53:33 AM9/12/09
to pyth...@googlegroups.com
可以用 gobject-introspection 自动通过 .h 文件分析 Glib 对象
然后自动生成 gtypes 的包装,

可有人愿意弄一下?

Jiahua Huang

unread,
Sep 12, 2009, 2:33:11 AM9/12/09
to pyth...@googlegroups.com
来点信号


#!/usr/bin/python3

# -*- coding: UTF-8 -*-



import ctypes

gobject = ctypes.CDLL('libgobject-2.0.so.0')

glib = ctypes.CDLL('libglib-2.0.so.0')

gtk = ctypes.CDLL('libgtk-x11-2.0.so.0')



gobject.g_type_init ()

gtk.gtk_init(None, None)



win = gtk.gtk_window_new(0)



gtk.gtk_window_set_title(win, ctypes.c_char_p("Gtk TextView"))

gtk.gtk_window_set_icon_name(win, ctypes.c_char_p("gtk-dnd"))

gtk.gtk_window_set_default_size(win, 300, 300)



gtk.gtk_signal_connect_full(win,

    ctypes.c_char_p("delete_event"),

    gtk.gtk_main_quit,

    None, None, None, 0, 0)



view = gtk.gtk_text_view_new()



buffer = gtk.gtk_text_view_get_buffer(view)

text = "Gtk TextView\n Text"

gtk.gtk_text_buffer_set_text(buffer, ctypes.c_char_p(text), len(text))



gtk.gtk_container_add(win, view)



gtk.gtk_widget_show_all(win)



gtk.gtk_main()


ziegler

unread,
Sep 12, 2009, 12:29:05 PM9/12/09
to python-cn`CPyUG`华蟒用户组(中文Py用户组)
这样子应用ctypes理论上可行,但是碰到一些C/C++味道很浓的库就难办了。特别是带有指针的。比如:

void foo(char** bar, struct ClassA* spam);

再者ctypes对于char[]型的处理,有时候用stringbuffer,有时候用c_char*n。总之,大大地麻烦唉。

On 9月12日, 下午12时19分, Jiahua Huang <jhuangjia...@gmail.com> wrote:
> Python3 现在还缺少许多 Python2 里可用的 C 库,如常见的 PyGtk不过既然 Python2.5 以后就自带了 ctypes

> Screenshot-Gtk WebKit.png
> 76K查看下载

Zoom.Quiet

unread,
Sep 12, 2009, 12:33:32 PM9/12/09
to pyth...@googlegroups.com
2009/9/13 ziegler <hgol...@gmail.com>:
> 这样子应用ctypes理论上可行,但是碰到一些C/C++味道很浓的库就难办了。特别是带有指针的。比如:
>
那俺们就不用,
毕竟C库历史忒 长,可以选择的库也忒多...

--
http://zoomquiet.org 人生苦短? Pythonic!
Free as in Freedom! 哲思社区:http://zeuux.com

pong Chong

unread,
Sep 12, 2009, 12:39:41 PM9/12/09
to pyth...@googlegroups.com
你们都忒列嘿

森南

unread,
Sep 12, 2009, 2:03:02 PM9/12/09
to pyth...@googlegroups.com
有没有用ctypes调用libcurl的方法, 去年我试了两天无果.

2009/9/12 Jiahua Huang <jhuang...@gmail.com>

est

unread,
Sep 12, 2009, 11:06:29 PM9/12/09
to python-cn`CPyUG`华蟒用户组(中文Py用户组)
话说us-python也该出q3了。。。不知googler们用20%的时间把GIL去掉没~~~

On Sep 12, 12:35 pm, Jiahua Huang <jhuangjia...@gmail.com> wrote:
> 大妈满塞~
> 那些抱怨 Py3 缺第三方 C 库的得没话说了~
>
> 再加上 google unladen-swallow 这个狂快的 VM,
> 足以在许多地方无缝掉 C 了~
>

> 2009/9/12 Zoom.Quiet <zoom.qu...@gmail.com>

Jiahua Huang

unread,
Sep 13, 2009, 2:44:26 AM9/13/09
to pyth...@googlegroups.com
如果目标仅限于 Glib/Gtk 相关库,
即代替 python2 里旧的 PyGtk 系 C 模块(Gtk、Gnome、VNC、GtkSourceView、WebKit 等)
那 ctypes 基本还是没问题的


2009/9/13 ziegler <hgol...@gmail.com>
这样子应用ctypes理论上可行,但是碰到一些C/C++味道很浓的库就难办了。特别是带有指针的。比如:



来个比较 pythonic 的封装


先包装下对象,模拟旧的 PyGtk 模块用法

gtk.py


#!/usr/bin/python3

# -*- coding: UTF-8 -*-



import types

import ctypes

_gobject = ctypes.CDLL('libgobject-2.0.so.0')

_glib = ctypes.CDLL('libglib-2.0.so.0')

_gtk = ctypes.CDLL('libgtk-x11-2.0.so.0')



def gtype(gclass, cid):

    gobject = type(gclass.__name__, (), dict(gclass.__dict__))

    gobject.__init__ = lambda self:None

    gobject._cid = cid

    return gobject()



def init(args=[]):

    return _gtk.gtk_init(None, None)

    #return _gtk.gtk_init(len(args), map(ctypes.c_char_p, args))

    pass



def main():

    _gtk.gtk_main()

    pass



def main_quit(*args):

    return _gtk.gtk_main_quit()

    pass



class GObject(object):

    _cid = 0

    def connect(self, signal_name, func, *args):

        cfunc = ctypes.CFUNCTYPE(ctypes.c_int)(func)

        return _gtk.gtk_signal_connect_full(self._cid,

                ctypes.c_char_p(signal_name),

                cfunc,

                None, None, None, 0, 0)

        pass

    pass



class Object(GObject):

    pass



class Widget(Object):

    def show(self):

        return _gtk.gtk_widget_show(self._cid)

    def show_all(self):

        return _gtk.gtk_widget_show_all(self._cid)

    pass



class Container(Widget):

    def add(self, child):

        return _gtk.gtk_container_add(self._cid, child._cid)

    pass



class Bin(Container):

    def get_child(self):

        return _gtk.gtk_bin_get_child(self._cid)

    pass





class Window(Bin):

    def __init__(self, window_type=0):

        self._cid = _gtk.gtk_window_new(window_type)

        pass

    def set_title(self, title):

        return _gtk.gtk_window_set_title(self._cid, ctypes.c_char_p(title))

        pass

    def set_icon_name(self, icon_name):

        return _gtk.gtk_window_set_icon_name(self._cid, ctypes.c_char_p(icon_name))

        pass

    def set_default_size(self, width, height):

        return _gtk.gtk_window_set_default_size(self._cid, width, height)

        pass

    pass





class TextBuffer(GObject):

    def __init__(self, table=None):

        _gtk.gtk_text_buffer_new()

        pass

    def set_text(self, text):

        return _gtk.gtk_text_buffer_set_text(

            self._cid,

            ctypes.c_char_p(text),

            len(text))

        pass

    pass



class TextView(Container):

    def __init__(self, buffer=None):

        self._cid = _gtk.gtk_text_view_new()

        pass

    def get_buffer(self):

        cid = _gtk.gtk_text_view_get_buffer(self._cid)

        buffer = gtype(TextBuffer, cid)

        return buffer

        pass

    pass


上边的模块用起来跟 python2 里的 PyGtk 一致

gtkwindow-example.py


#!/usr/bin/python3
# -*- coding: UTF-8 -*-



import gtk



def main():

    gtk.init()

    # 创建一个窗口对象

    win = gtk.Window()

    # 设置标题等属性

    win.set_title("Gtk Window")

    win.set_default_size(300, 300)

    win.set_icon_name("gtk-dnd")

    # 创建一个 文本框对象,并弄点文字

    view = gtk.TextView()

    buffer = view.get_buffer()

    buffer.set_text("Gtk TextView\n Text")

    # 将 文本框 弄到 窗口里

    win.add(view)

    def on_quit(widget=None):

        gtk.main_quit()

        pass

    # 搞个窗口关闭事件

    win.connect("delete_event", on_quit)

    # 显示窗口(及子部件)

    win.show_all()

    # 启动主循环

    gtk.main()

    pass



if __name__=="__main__":

    main()

    pass

如图,运行后显示了一个带文本框的 Gtk 窗口

Gtk Window.png

确实这个例子只封装了很少的对象,不过也表明这样是可行的,
哪位有空的话,可以利用 gobject-introspection 来分析 .h 头文件,自动生成封装

Gtk Window.png

eric

unread,
Sep 13, 2009, 6:39:27 AM9/13/09
to pyth...@googlegroups.com
非常不错

2009/9/13 Jiahua Huang <jhuang...@gmail.com>

pan shizhu

unread,
Sep 14, 2009, 4:02:41 AM9/14/09
to pyth...@googlegroups.com

记得我刚学python的时候就问过这个问题,不过一直没有答案。

既然ctype可以解决很多问题,为什么还需要专用库绑定呢?

我得到的一个答案是:ctype方式的效率比不上专业的库绑定。但是我没有亲自测试过。希望谁能证实一下。
至少我自己可以证明对于 lua 来讲,lua_ctype方式的效率比不上直接写C语言函数绑定。python谁有能力的请证实一下这个说法是对还是错。

另外一个可能的答案是:在处理char *这样的类型问题上,ctype确实会时不时的遇到一些麻烦,毕竟对于C语言来说,char *的用法不下十种。而你不能总把它当作常规的字符串去用。


Yin Desheng

unread,
Sep 14, 2009, 6:37:06 AM9/14/09
to pyth...@googlegroups.com
char *  除了可以用ctypes.c_char_p表示外,还可以用 ctypes.c_byte * N 来表示。

2009/9/14 pan shizhu <pan.s...@gmail.com>

Yin Desheng

unread,
Sep 14, 2009, 9:00:13 AM9/14/09
to pyth...@googlegroups.com
关于如何表示char**, 我的方法比较麻烦, 不知有没更好的方法。
Chars = c_byte * 3
Charss = POINTER(Chars) * 3
data = Charss(pointer(Chars(1,2,3)), pointer(Chars(4,5,6)), pointer(Chars(7,8,9)))

Reply all
Reply to author
Forward
0 new messages