2010-01-31 48 views
9

Chương trình của tôi vẽ vòng tròn di chuyển trên cửa sổ. Tôi nghĩ rằng tôi phải thiếu một số khái niệm gtk/cairo cơ bản bởi vì nó dường như đang chạy quá chậm/nói lắp cho những gì tôi đang làm. Ý tưởng nào? Cảm ơn vì bất kì sự giúp đỡ!Tại sao chương trình python gtk + cairo đơn giản của tôi chạy chậm/nói lắp?

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

Chương trình tuyệt vời! Tôi sẽ cố gắng để ngẫu nhiên tô màu các quả bóng để làm một số mắt trơn kẹo; o) – heltonbiker

Trả lời

10

Một trong những vấn đề là bạn đang vẽ cùng một đối tượng cơ bản lặp đi lặp lại. Tôi không chắc chắn về GTK + đệm hành vi, nhưng cũng nên nhớ rằng các cuộc gọi chức năng cơ bản phải chịu một chi phí bằng Python. Tôi đã thêm một bộ đếm khung cho chương trình của bạn, và tôi với mã của bạn, tôi nhận được khoảng 30fps tối đa.

Có một số việc bạn có thể thực hiện, ví dụ: tạo đường dẫn lớn hơn trước khi thực sự gọi bất kỳ phương thức điền hoặc đột quỵ nào (tức là tất cả sẽ phát trong một cuộc gọi). Một giải pháp khác, nhanh hơn rất nhiều là soạn bóng của bạn trong bộ đệm ngoài màn hình và sau đó chỉ vẽ lên màn hình nhiều lần:

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

Điều này mang lại khoảng 273 fps trên máy tính của tôi. Bởi vì điều này, bạn nên suy nghĩ về việc sử dụng gobject.timeout_add thay vì idle_add.

+0

Có cách nào để sử dụng phương pháp này nhanh hơn trong khi có thể thiết lập màu sắc của vòng tròn tại thời gian vẽ? Cảm ơn! – shino

+0

Không có gì mà tôi biết (mà không làm nhiều nghiên cứu), bạn sẽ phải tạo ra một số hình ảnh trước. –

+5

Các nút cổ chai thực sự trong cairo là thế hệ mặt nạ, vì vậy bạn có thể tạo ra nó trước và điền vào nhiều lần với các nguồn khác nhau. Đây là luồng cairo có liên quan (chi tiết triển khai trong C mặc dù): http://lists.cairographics.org/archives/cairo/2009-October/018243.html – ntd

2

Tôi không thấy bất kỳ điều gì sai về cơ bản với mã của bạn. Để thu hẹp sự cố, tôi đã thử một cách tiếp cận khác có thể tối thiểu nhanh hơn, nhưng sự khác biệt gần như không đáng kể:

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

Ngoài ra, ghi đè lên không có sự khác biệt lớn.

Tôi có thể thử danh sách gửi thư của Cairo hoặc xem Clutter hoặc pygame để vẽ một số lượng lớn các mục trên màn hình.

0

Tôi gặp vấn đề tương tự trong chương trình được viết trên C#. Trước khi bạn rời khỏi sự kiện Expose, hãy thử viết cr.dispose().

Các vấn đề liên quan