11

私のプログラムは、ウィンドウ上を移動する円を描画します。私がやっていることに対して実行が遅すぎる/途切れ途切れに見えるので、基本的な 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()
4

3 に答える 3

12

問題の1つは、同じ基本オブジェクトを何度も描画していることです。GTK +のバッファリング動作についてはよくわかりませんが、Pythonでは基本的な関数呼び出しにコストがかかることにも注意してください。私はあなたのプログラムにフレームカウンターを追加しました、そして私はあなたのコードで、私は最大でおよそ30fpsを得ました。

実行できることがいくつかあります。たとえば、実際に塗りつぶしやストロークのメソッドを呼び出す前に、より大きなパスを作成します(つまり、1回の呼び出しですべての円弧を作成します)。非常に高速な別の解決策は、画面外のバッファーでボールを作成し、それを画面に繰り返しペイントすることです。

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

これにより、私のマシンで約273fpsが得られます。gobject.timeout_addこのため、ではなく使用を検討する必要がありますidle_add

于 2010-02-01T00:16:56.970 に答える
2

あなたのコードに根本的な問題はありません。問題を絞り込むために、最低限高速な別のアプローチを試しましたが、違いはほとんどありません。

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

また、DrawingArea.draw() をスタブでオーバーライドしても大きな違いはありません。

おそらく Cairo メーリング リストを試すか、Clutter や pygame を使って画面上に大量のアイテムを描画する方法を検討したいと思います。

于 2010-01-31T18:14:25.853 に答える
0

C#で書かれたプログラムでも同じ問題が発生しました。Exposeイベントを去る前に、書いてみてくださいcr.dispose()

于 2010-06-10T04:14:48.347 に答える