2012-04-22 20 views
6

Tengo una pequeña aplicación que usa un DrawingArea para dibujar un mapa simple usando PyGObject y GTK3.Cómo dibujar un GdkPixbuf usando GTK3 y PyGObject

cargo un Pixbuf usando

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

y luego tratar de dibujar en el DrawingArea 's dibujar señal de evento

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

pero me sale el mensaje de error

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

Si estoy leyendo el Gtk2 to Gtk3 migration guide correctamente, esto debería funcionar. ¿Qué estoy haciendo mal?

+0

¿Seguro que está recibiendo algo de vuelta de dibujable get_window ? – stark

+0

Sí, obtengo un objeto '', por lo que se realiza el widget DrawingArea. Parece que no sé cómo se supone que funciona el dibujo de pixbufs en Gtk3. – gnirx

Respuesta

9

El nuevo dibujar señal utiliza una devolución de llamada que ya pasa el contexto Cairo como un parámetro, que no es necesario hacer cosas como window = widget.get_window() como lo hizo en PyGtk para obtener el contexto Cairo para asistir a la exponer al evento señal. En PyGObject es más simple:

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 

Esto es, si usted no necesita la pixbuf, pero si que lo necesite para algo más que usted tiene varias opciones:

  1. tener los dos objetos en memoria. Si ambos se cargan desde un PNG, no debería haber muchos problemas además de la pérdida de memoria.
  2. Convierte GdkPixbuf a PIL Image, luego PIL Image a data array y luego crea una Cairo ImageSurface desde esa matriz de datos usando create_for_data(). Yak: S No sé mejor, lo siento: S
  3. Use Gdk.cairo_set_source_pixbuf() propuesto por hock. Esta parece ser la forma correcta de dibujar un Pixbuf en una superficie de imagen, pero es totalmente antiponético (y es por eso que odio este tipo de introspección, todo se ve como C, como un mal puerto de C).

Si elige la segunda opción horrible aquí es cómo:

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) 

Tenga en cuenta que create_for_data() esnot yet available for Python3, only for Python2.

Check también mi respuesta sobre cómo usar un tampón doble en PyGObject si esto es lo que estamos tratando de lograr: Drawing in PyGobject (python3)

Saludos cordiales

+0

Gracias. Esta parece ser una manera mucho más segura de manejar gráficos en GTK3 que mis diversos esfuerzos;) – gnirx

+2

+1 "pero es totalmente antiponético (y es por eso que odio este tipo de introspección, todo parece C, como un mal puerto C). " – xubuntix

6

El siguiente parece hacer el trabajo:

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

Una pregunta sigue siendo: ¿Es esta la mejor forma de hacer las cosas?

+1

mi programa genera "fallas de segmentación" después de ejecutar '' cairo_set_source_pixbuf'' ¿Alguna ayuda? –

+0

En Gtk doc dicen "ten cuidado, esta función no es de El Cairo ...". Debería -1 la respuesta anterior a esta, pero parece ser más constructivo que +1. Gtk3 es una forma diferente de cosas, usa cairo y devuelve el controlador a la superficie, por lo que no actúes como si fuera una herramienta externa: allí es donde los dibujos ocurren. – cox

+1

@AkashShende - También estoy obteniendo un error de segmentación con '.cairo_get_source_pixbuf', ¿descubrió cómo solucionarlo? – nluigi

Cuestiones relacionadas