如何使用GTK3和PyGObject绘制GdkPixbuf

时间:2012-04-22 17:05:54

标签: python gtk3 pygobject

我有一个小应用程序使用DrawingArea使用PyGObjectGTK3绘制简单地图。

我使用

加载Pixbuf
from gi.repository import Gtk, GdkPixbuf
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size("logo.png", 25, 25)

然后尝试在DrawingArea的绘制事件信号中绘制它

def draw(self, widget, context):
    window = widget.get_window()
    ctx = window.cairo_create()
    ctx.set_source_pixbuf(pixbuf, 0, 0)

但我收到错误消息

"AttributeError: 'cairo.Context' object has no attribute 'set_source_pixbuf'"

如果我正确地阅读Gtk2 to Gtk3 migration guide,这应该可行。 我做错了什么?

2 个答案:

答案 0 :(得分:10)

新的 draw 信号使用已经将cairo上下文作为参数传递的回调,你不需要像在PyGtk中那样做window = widget.get_window()之类的东西来获取cairo在参加 expose-event 信号时的上下文。在PYGObject中更简单:

import cairo

class Foo(object):
    def __init__(self):

       (...)
        self.image = cairo.ImageSurface.create_from_png('logo.png')
       (...)

    def draw(self, widget, context):
        if self.image is not None:
            context.set_source_surface(self.image, 0.0, 0.0)
            context.paint()
        else:
            print('Invalid image')
        return False

那就是如果你不需要PixBuf,但如果你需要它来做其他事情你有几个选择:

  1. 将两个对象都放在内存中。如果两者都是从PNG加载的,那么除了浪费内存之外,应该没有太多问题。
  2. 将GdkPixbuf转换为PIL Image,然后将PIL Image转换为数据阵列,然后使用create_for_data()从该数据阵列创建Cairo ImageSurface。牦牛:我不知道更好,对不起:S
  3. 使用hock提出的 Gdk.cairo_set_source_pixbuf()。这似乎是在ImageSurface中绘制Pixbuf的正确方法,但它完全是unpythonic(这就是为什么我讨厌这个Introspection的东西,所有看起来像C,就像一个糟糕的C端口)。
  4. 如果你选择了糟糕的第二个选项,那么:

    import Image
    import array
    from gi.repository import Gtk, GdkPixbuf
    
    width = 25
    height = 25
    pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('logo.png', width, height)
    pil_image = Image.fromstring('RGBA', (width, height), pixbuf.get_pixels())
    byte_array = array.array('B', pil_image.tostring())
    cairo_surface = cairo.ImageSurface.create_for_data(byte_array, cairo.FORMAT_ARGB32, width, height, width * 4)
    

    请注意 create_for_data()not yet available for Python3only for Python2

    如果这是你想要实现的目标,请查看我在PyGObject中如何使用双缓冲区的答案:Drawing in PyGobject (python3)

    亲切的问候

答案 1 :(得分:7)

以下似乎可以完成这项工作:

def draw(self, widget, context):
    Gdk.cairo_set_source_pixbuf(context, self.pixbuf, 0, 0)
    context.paint()

仍然存在一个问题:这是首选方式吗?