10

我有一个小应用程序,它使用 a和DrawingArea绘制简单的地图。PyGObjectGTK3

我加载一个Pixbuf使用

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

然后尝试在DrawingArea's draw 事件信号中绘制它

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 到 Gtk3 迁移指南,这应该可以。我究竟做错了什么?

4

2 回答 2

10

新的绘图信号使用一个已经将 cairo 上下文作为参数传递的回调,您不需要window = widget.get_window()像在 PyGtk 中所做的那样在参加暴露事件信号时获取 cairo 上下文。在 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 图像,然后将 PIL 图像转换为数据数组,然后使用 create_for_data() 从该数据数组创建 Cairo ImageSurface。牦牛:SI不知道更好,对不起:S
  3. 使用hock提出的Gdk.cairo_set_source_pixbuf() 。这似乎是在 ImageSurface 中绘制 Pixbuf 的正确方法,但它完全不是 Python 的(这就是为什么我讨厌这种 Introspection 的东西,所有看起来都像 C,就像一个糟糕的 C 端口)。

如果您选择糟糕的第二个选项,方法如下:

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()尚不适用于 Python3仅适用于 Python2

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

亲切的问候

于 2012-05-11T07:16:59.470 回答
8

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

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

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

于 2012-04-23T19:48:50.133 回答