Python + Cairo + GTK/GDK 像素缓冲区的简单设置
为了我自己的学习和可能的教育用途,我想为Python和Cairo制作一个类似pygame的API。但我不想让它完全和pygame一样。我希望它能成为一个半静态的绘图平台,能够使用GTK/GDK显示一张或多张图片,并且我想模仿TiKZ(一个latex包)优秀的API设计原则。虽然PyGame的API还不错,但我对它不太满意。有一个特别的问题是,我希望这个包能通过将所有内容绘制到一个pixbuf(使用Cairo)来处理窗口刷新,并在窗口被遮挡时自动重绘这个pixbuf。这样,最终的程序员就不需要担心窗口刷新了。实际上,最终的程序员不应该需要写任何类或函数,只需要一行行简单的代码就能画出一个笑脸(比如说)。这个图形库也不需要像TkInter那样维护一个越来越长的形状对象列表。(至少,我希望Cairo不会违背我的意图。)
我在pycairo中成功地绘制了各种东西,并将输出到ImageMagick和Postscript。所以我对pycairo本身是没问题的。
不幸的是,我找到的cairo/gtk/pycairo/pygtk文档——我不知道它是为谁写的,但显然不是为我写的。目前,我是一个像Project Euler那样的程序员,而不是那种“5个超前沿的面向对象API”的程序员。我希望能看到清晰的操作说明,或者一个明确的示例。
好的,我接受了一个回答,因为它至少有点帮助。但这里简而言之,真正的问题是,GDK在你使用Cairo绘制东西时会创建一个临时双缓冲区。预计当你处理一个暴露事件时,你会重新绘制所有内容。但如果你有一个非常复杂的图像,这个过程会很慢,尤其是在Python中。所以如果Cairo能写入一个永久双缓冲区而不是临时的,那就太好了,然后这个永久双缓冲区会通过GDK暴露出来。许多开发者都想要解决这个问题。似乎有一个项目提供了一种解决方案,那就是Google Chromium——你有没有注意到在Linux上Google Chrome的窗口暴露效果有多好?所以我会查看Chromium的源代码,看看我能否轻松实现这个。
附录:我看到我在提到“pixbufs”时确实让问题变得复杂了。我其实不太关心pixbufs(我又改了问题标题)。我真正关心的是在Cairo和GTK/GDK之间创建一个永久的双缓冲像素数组,而不是一个临时的双缓冲像素数组。似乎实现这个的最简单方法是把GTK窗口变成一个Cairo表面,把双缓冲区变成另一个Cairo表面。由于我在问题中请求了一个示例,这里有一些:
class Canvas(gtk.DrawingArea):
def __init__(self):
super(Canvas, self).__init__()
self.connect("expose_event", self.expose)
self.set_size_request(width,height)
def expose(self, widget, event):
cr = widget.window.cairo_create()
cr.set_source_surface(mybuffer,0,0)
cr.paint()
另一个很快出现的棘手问题是,我希望这是一个WYSIWYG绘图环境,能够立即绘制Python要求它绘制的内容——而且可以扩展到动画。然而,大多数GTK示例并不是这样设置的:事件处理被推迟,直到我调用gtk.main()
。 (或者在Python中,我惊讶地发现raw_input()
也以某种方式刷新了GTK事件队列。)我找到了一些不错的解释,包含Python示例,说明了如何不把事件控制权交给GTK。最简单的解决方案,可能也是我将采用的,是在你想要刷新事件缓冲区时使用这个:
while gtk.events_pending(): gtk.main_iteration(False)
还有最后一件事,我需要刷新像素缓冲区和事件缓冲区。看起来实现这个的一种方法是window.queue_draw()