通过gobject.timeout_add回调函数用cairo绘制一个点

时间:2013-11-27 15:51:46

标签: python gtk cairo gobject

我有一个差不多工作的代码(我希望)。在这个类的更新方法中,应该在由窗口的宽度和高度限定的位置绘制随机黑点 - 问题是没有绘制点。将显示一个gtk窗口,其中包含使用cairo ImageSurface.create_from_png(BG_IMG)加载的背景图像,并且我还验证了调用更新函数(每隔17ms使用gobject.timeout_add回调函数)。我在这里和其他地方搜索过,但我不太清楚这段代码有什么问题。

class Screen(gtk.DrawingArea):

    __gsignals__ = {"expose-event": "override"}

    def do_expose_event(self, event):
        self.cr = self.window.cairo_create()

        self.cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
        self.cr.clip()
        self.draw(*self.window.get_size())

    def draw(self, width, height):
        x = y = 0
        self.bg = c.ImageSurface.create_from_png(BG_IMG)
        self.cr.set_source_surface(self.bg, x, y)
        self.cr.paint()

    def update(self):
        x = randint(0, DOCK_W)
        y = randint(0, DOCK_H)
        self.cr.rectangle(x, y, 1, 1)
        self.cr.set_source_rgba(0, 0, 0, 1)
        self.cr.fill()
        self.cr.paint()

有人对这个代码失败的原因有一些了解吗?非常感谢提前!

解决

我不知道每个绘制操作都可以使用新的cairo上下文。结果证明这是主要问题。

1 个答案:

答案 0 :(得分:1)

一般来说,您不应直接在曝光事件之外绘制窗口。并且不要保留cairo上下文以供以后使用:为每个事件运行创建一个。

如果您想绘制积分,只需执行:widget.queue_draw(),并尽快向您发送新的展示事件。但请注意,在曝光事件中,您必须绘制所有点,而不仅仅是新点。

对您的代码类型进行了有用的优化:来自计时器不会调用queue_draw,因为它效率很低。相反,只需绘制新点。但是,这并不能成为您在do_expose_event中绘制所有点的借口,因为暴露事件可能随时发生,您不希望丢失已绘制的点。

要进行单点绘制,您必须创建一个新的cairo上下文,但不需要保存它:

def update(self):
    cr = self.window.cairo_create()
    x = randint(0, DOCK_W)
    y = randint(0, DOCK_H)
    self.points.append((x,y)) #for the expose event ;-)
    cr.rectangle(x, y, 1, 1)
    cr.set_source_rgba(0, 0, 0, 1)
    cr.fill()
    cr.paint()

另一个常见的优化,特别是如果你有很多点是将绘制的图像保持在位图中,所以当曝光事件发生时,你只需要对位图进行blit,而不是遍历点列表。