2010-01-31 2 views
9

내 프로그램이 창에서 움직이는 원을 그립니다. 내가 약간의 gtk/cairo 개념을 놓치고 있어야한다고 생각한다. 왜냐하면 그것이 내가하고있는 일에 너무 천천히/말을 걸어 다니는 것처럼 보이기 때문이다. 어떤 아이디어? 어떤 도움을 주셔서 감사합니다!왜 내 간단한 파이썬 gtk + cairo 프로그램이 너무 느리게/달리는 지요?

#!/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

멋진 프로그램! o) – heltonbiker

답변

10

문제 중 하나는 동일한 기본 개체를 반복해서 그리는 것입니다. GTK + 버퍼링 동작에 대해서는 잘 모르겠지만 기본 함수 호출이 파이썬에서 비용을 발생 시킨다는 사실을 명심하십시오. 귀하의 프로그램에 프레임 카운터를 추가했습니다. 코드를 사용하면 최대 30fps가됩니다.

실제로 할 수있는 일은 여러 가지가 있습니다. 예를 들어 필 또는 스트로크 메소드를 실제로 호출하기 전에 더 큰 경로를 작성하는 것입니다 (예 : 단일 호출에서 모든 호가 표시됨).

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()) 

이 내 컴퓨터에 약 273 FPS를 제공합니다 훨씬 빠른 또 다른 해결책은, 오프 스크린 버퍼에 공을 작성하고 다음 반복 해 화면에 칠하는 것입니다. 이 때문에 idle_add 대신 gobject.timeout_add을 사용하는 것이 좋습니다.

+0

그리기 시간에 원의 색을 설정하는 동안이 빠른 방법을 사용할 수있는 방법이 있습니까? 감사합니다. – shino

+0

많은 연구를하지 않고서도 내가 아는 사실이라면 미리 여러 ​​이미지를 만들어야 할 것입니다. –

+5

카이로의 진정한 병목 현상은 마스크 생성이므로 사전에 생성하고 다른 소스로 더 많은 시간을 채울 수 있습니다. 이것은 관련된 카이로 스레드 (C의 구현 세부 사항)입니다. http://lists.cairographics.org/archives/cairo/2009-October/018243.html – ntd

2

코드에 근본적으로 잘못된 것이 없습니다. 이 문제를 좁히려 나는 최소한 빠를 수 있습니다 다른 접근 방식을 시도했지만 차이는 거의 무시할 : 그루터기와 DrawingArea.draw()를 오버라이드 (override) 또한

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() 

, 더 큰 차이가 없습니다.

나는 아마도 카이로 메일 링리스트를 시험해 보거나 화면에 많은 수의 항목을 그리기 위해 클러 터 (clutter) 또는 파이 게임 (pygame)을 살펴볼 것이다.

0

나는 프로그램에서 C와 동일한 문제가 발생했습니다. Expose 이벤트를 떠나기 전에 cr.dispose()을 작성하십시오.

관련 문제