我有一个差不多工作的代码(我希望)。在这个类的更新方法中,应该在由窗口的宽度和高度限定的位置绘制随机黑点 - 问题是没有绘制点。将显示一个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上下文。结果证明这是主要问题。
答案 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,而不是遍历点列表。