2010-01-31 12 views
9

Mój program rysuje kółka poruszające się po oknie. Myślę, że brakuje mi jakiejś podstawowej koncepcji gtk/cairo, ponieważ wydaje się, że działa ona zbyt wolno/jąkająco na to, co robię. Jakieś pomysły? Dzięki za pomoc!Dlaczego mój prosty program python gtk + cairo działa tak wolno/jąkająco?

#!/usr/bin/python 

import gtk 
import gtk.gdk as gdk 
import math 
import random 
import gobject 

# The number of circles and the window size. 
num = 128 
size = 512 

# Initialize circle coordinates and velocities. 
x = [] 
y = [] 
xv = [] 
yv = [] 
for i in range(num): 
    x.append(random.randint(0, size)) 
    y.append(random.randint(0, size)) 
    xv.append(random.randint(-4, 4)) 
    yv.append(random.randint(-4, 4)) 


# Draw the circles and update their positions. 
def expose(*args): 
    cr = darea.window.cairo_create() 
    cr.set_line_width(4) 
    for i in range(num): 
     cr.set_source_rgb(1, 0, 0) 
     cr.arc(x[i], y[i], 8, 0, 2 * math.pi) 
     cr.stroke_preserve() 
     cr.set_source_rgb(1, 1, 1) 
     cr.fill() 
     x[i] += xv[i] 
     y[i] += yv[i] 
     if x[i] > size or x[i] < 0: 
      xv[i] = -xv[i] 
     if y[i] > size or y[i] < 0: 
      yv[i] = -yv[i] 


# Self-evident? 
def timeout(): 
    darea.queue_draw() 
    return True 


# Initialize the window. 
window = gtk.Window() 
window.resize(size, size) 
window.connect("destroy", gtk.main_quit) 
darea = gtk.DrawingArea() 
darea.connect("expose-event", expose) 
window.add(darea) 
window.show_all() 


# Self-evident? 
gobject.idle_add(timeout) 
gtk.main() 
+0

Niezły program! Próbowałbym losowo pokolorować kulki, żeby zrobić zwykły cukierek do oczu; o) – heltonbiker

Odpowiedz

10

Jednym z problemów jest ciągłe rysowanie tego samego podstawowego obiektu. Nie jestem pewien co do zachowania bufora GTK +, ale należy również pamiętać, że podstawowe wywołania funkcji wiążą się z kosztem w Pythonie. Dodałem licznik klatek do twojego programu, a ja z twoim kodem uzyskałem około 30 fps max.

Jest kilka rzeczy, które można zrobić, na przykład komponować większe ścieżki przed wywołaniem dowolnej metody wypełnienia lub obrysu (tzn. Wszystkie łuki w jednym wywołaniu). Innym rozwiązaniem, które jest znacznie szybciej jest skomponować piłkę w buforze off-screen a potem po prostu pomalować go na ekranie wielokrotnie:

def create_basic_image(): 
    img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 24, 24) 
    c = cairo.Context(img) 
    c.set_line_width(4) 
    c.arc(12, 12, 8, 0, 2 * math.pi) 
    c.set_source_rgb(1, 0, 0) 
    c.stroke_preserve() 
    c.set_source_rgb(1, 1, 1) 
    c.fill() 
    return img 

def expose(sender, event, img): 
    cr = darea.window.cairo_create() 
    for i in range(num): 
     cr.set_source_surface(img, x[i], y[i])   
     cr.paint() 
     ... # your update code here 

... 
darea.connect("expose-event", expose, create_basic_image()) 

Daje to około 273 fps na moim komputerze. Z tego powodu powinieneś pomyśleć o użyciu gobject.timeout_add zamiast idle_add.

+0

Czy jest jakiś sposób, aby użyć tej szybszej metody, będąc w stanie ustawić kolor koła w czasie gry? Dzięki! – shino

+0

Nic, co wiem (bez wykonywania wielu badań), musiałbyś wcześniej stworzyć kilka obrazów. –

+5

Prawdziwym wąskim gardłem w Kairze jest generowanie masek, dzięki czemu można je tworzyć z wyprzedzeniem i wypełniać więcej razy różnymi źródłami. To jest odpowiedni wątek cairo (szczegóły implementacji w C): http://lists.cairographics.org/archives/cairo/2009- October/018243.html – ntd

2

Nie widzę nic zasadniczo nie tak z Twoim kodem. Aby zawęzić problem w dół Próbowałem innego podejścia, które mogą być minimalnie szybszy, ale różnica jest znikomy:

class Area(gtk.DrawingArea): 
    def do_expose_event(self, event): 
     cr = self.window.cairo_create() 

     # Restrict Cairo to the exposed area; avoid extra work 
     cr.rectangle(event.area.x, 
        event.area.y, 
        event.area.width, 
        event.area.height) 
     cr.clip() 

     cr.set_line_width(4) 
     for i in range(num): 
      cr.set_source_rgb(1, 0, 0) 
      cr.arc(x[i], y[i], 8, 0, 2 * math.pi) 
      cr.stroke_preserve() 
      cr.set_source_rgb(1, 1, 1) 
      cr.fill() 
      x[i] += xv[i] 
      y[i] += yv[i] 
      if x[i] > size or x[i] < 0: 
       xv[i] = -xv[i] 
      if y[i] > size or y[i] < 0: 
       yv[i] = -yv[i] 
     self.queue_draw() 

gobject.type_register(Area) 

# Initialize the window. 
window = gtk.Window() 
window.resize(size, size) 
window.connect("destroy", gtk.main_quit) 
darea = Area() 
window.add(darea) 
window.show_all() 

Również nadrzędnymi DrawingArea.draw() z odgałęzienie nie ma większej różnicy.

Najprawdopodobniej wypróbuję listę mailingową w Kairze lub przyjrzę się bałaganem lub pygame w celu narysowania dużej liczby elementów na ekranie.

0

Mam ten sam problem w programie został napisany na C#. Zanim opuścisz Expose zdarzenie, spróbuj napisać cr.dispose().

Powiązane problemy