2012-04-22 10 views
6

Mam małą aplikację, która używa DrawingArea, aby narysować prostą mapę przy użyciu PyGObject i GTK3.Jak narysować GdkPixbuf przy użyciu GTK3 i PyGObject

załadować Pixbuf użyciu

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

a następnie spróbuj wyciągnąć go w DrawingArea „s wyciągnąć sygnał zdarzenia

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

ale pojawia się komunikat o błędzie

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

Jeśli poprawnie czytam Gtk2 to Gtk3 migration guide, powinno to działać. Co robię źle?

+0

Czy jesteś pewien, że dostajesz coś rozciągliwej z powrotem get_window ? – stark

+0

Tak, otrzymuję obiekt ' obiekt' 'wstecz ', więc widget DrawingArea jest realizowany. Wydaje mi się, że nie rozumiem, jak działa pixbufs w Gtk3. – gnirx

Odpowiedz

9

Nowy narysować sygnału zwrotnego, który wykorzystuje już przechodzi kontekst Kairu parametru, nie trzeba robić rzeczy, jak window = widget.get_window() jak ty w pygtk dostać kontekst cairo uczestnicząc w narazić-zdarzenie Sygnał. W PYGObject jest prostsza:

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 

To znaczy, jeśli nie potrzebujemy PixBuf, ale jeśli jest to potrzebne do czegoś innego masz kilka opcji:

  1. mieć oba obiekty w pamięci. Jeśli oba są ładowane z pliku PNG, nie powinno być większych problemów niż strata pamięci.
  2. Konwersja GdkPixbuf do obrazu PIL, następnie obraz PIL do tablicy danych, a następnie utworzenie z tej tablicy danych obiektu Kair ImageSurface za pomocą create_for_data(). Yak: S Nie wiem lepiej, przepraszam: S
  3. Użyj Gdk.cairo_set_source_pixbuf() zaproponowany przez hock. Wydaje się, że jest to właściwy sposób na narysowanie Pixbuf w ImageSurface, ale jest całkowicie niepythoniczny (i dlatego nienawidzę tego Introspekcja, wszystko wygląda jak C, jak zły port C).

Jeśli wybierzesz drugą opcję strasznie tutaj jest jak:

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) 

Zauważ, że create_for_data() jest not yet available for Python3, only for Python2.

Sprawdź też moja odpowiedź na temat korzystania z podwójną bufor w PyGObject jeśli to jest to, co starasz się osiągnąć: Drawing in PyGobject (python3)

poważaniem

+0

Dzięki. Wydaje się, że jest to o wiele lepszy sposób obsługi grafiki w GTK3 niż moje rozmaite wysiłki;) – gnirx

+2

+1 "ale jest całkowicie niepythoniczny (i dlatego nienawidzę tego Introspekcja, wszystko wygląda jak C, jak zły port C). " – xubuntix

6

Poniższa wydaje się wykonać zadanie:

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

Jedno pytanie pozostaje: Czy to preferowany sposób robienia rzeczy?

+1

mój program generuje "błędy segmentacji" po wykonaniu '' cairo_set_source_pixbuf'' jakiejkolwiek pomocy? –

+0

W dokumencie Gtk mówią: "bądź ostrożny, ta funkcja nie pochodzi z Kairu ...". Powinienem -1 odpowiedź powyżej, ale wydaje się bardziej konstruktywny, aby dać +1 temu. Gtk3 jest różny, używa kairu i oddaje go na powierzchnię, więc nie działaj tak, jakby był narzędziem zewnętrznym: zdarzają się rysunki. – cox

+1

@AkashShende - Otrzymuję również błąd segmentacji za pomocą '.cairo_get_source_pixbuf', czy wiesz, jak to naprawić? – nluigi