Как нарисовать GdkPixbuf с помощью GTK3 и PyGObject

у меня есть небольшое приложение, которое использует DrawingArea чтобы нарисовать простую карту, используя PyGObject и GTK3.

Я Pixbuf используя

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

а затем попробуйте нарисовать его в DrawingArea's draw event signal

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 руководство по миграции правильно, это должно работать. Что я делаю не так?

2 ответов


новая ничья сигнал использует обратный вызов, который уже передает контекст cairo в качестве параметра, Вам не нужно делать такие вещи, как window = widget.get_window() Как вы сделали в PyGtk, чтобы получить контекст Каира во время посещения 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 в массив данных, а затем создать Cairo ImageSurface из этого массива данных с помощью create_for_data (). Як: S Я не знаю лучше, извините: S
  3. использовать Gdk.cairo_set_source_pixbuf() предложено hock. Это, кажется, правильный способ сделать Pixbuf в ImageSurface, но это совершенно unpythonic (и вот почему я ненавижу этот самоанализ материал, все выглядит как 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 () is пока недоступно для Python3, только для Python2.

посмотри мой ответ о том, как использовать двойной буфер в PyGObject, если это то, что вы пытаетесь достичь: рисование в PyGobject (python3)

С уважением


следующее, кажется, делает эту работу:

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

остается один вопрос: Является ли это предпочтительным способом делать вещи?