Python 的简单设置开罗 + 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,GDK 会创建一个临时双缓冲区。预计当您处理暴露事件时,您将重新绘制所有内容。但如果你有一个非常复杂的图像,这是一个缓慢的过程,尤其是在 Python 中。因此,如果 Cairo 能够写入永久双缓冲区而不是临时双缓冲区,然后该永久双缓冲区将通过 GDK 公开,那就更好了。一些开发人员希望找到一个解决方案来解决这个问题。 Google Chromium 是似乎有某种解决方案的项目之一——您是否注意到 Google Chrome 中(例如 Linux 中)的窗口曝光效果有多么出色?所以我会查看 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()
另一个很快出现的棘手问题是我希望这是一个所见即所得的绘图环境,它可以立即绘制 Python 要求它绘制的内容 --- 并且可以扩展到动画。然而,大多数 GTK 示例并不是这样设置的:事件处理被推迟,直到我调用 gtk.main() 为止。 (或者在Python中,我惊讶地发现raw_input()
也以某种方式刷新GTK事件队列。)我发现一个很好的解释,带有 Python 示例,说明了将事件控制权交给 GTK 的替代方案。最简单的解决方案,也可能是我将采用的解决方案,是在您想要执行此操作时使用它来刷新事件缓冲区:
while gtk.events_pending(): gtk.main_iteration(False)
我还需要最后一件事,刷新像素缓冲区以及事件缓冲区。看起来一种方法是 window.queue_draw()
For my own benefit and possibly for educational use, I would like to make a pygame-like API for Python and Cairo. But I don't want it to be exactly pygame. I would instead like to make it a semi-static drawing platform that display one or more images using GTK/GDK, and I would like to imitate the excellent API principles of TiKZ (the latex package). The PyGame API is not bad, but I'm not satisfied with it. One particular issue is that I would like the package to handle window refresh by drawing everything into a pixbuf (with Cairo), and automatically redraw the pixbuf when the window is uncovered. That way the end programmer doesn't have to worry about window refresh. In fact, the end programmer shouldn't have to write a single class or function or any more than a straight sequence of lines of code to draw a smiley face (say). The graphics library also doesn't have to maintain an ever-longer list of stored shape objects as is the case in TkInter. (At least, I hope that Cairo doesn't do that against my intentions.)
I succeeded in drawing various things in pycairo with output to ImageMagick and Postscript. So I'm okay with pycairo itself.
Unfortunately, the cairo/gtk/pycairo/pygtk documentation that I found --- I don't know who it's written for, but not for me. At the moment, I am a Project Euler type of programmer, not a "5 bleeding edge ultra-object-oriented APIs" type of programmer. I'd like to see a clear explanation of what to do, and/or a clear example.
Okay, I accepted the one answer that was posted because it was at least a little helpful. But here in a nutshell is the real point. The point is that GDK make a temporary double buffer when you draw things in GDK, including using Cairo. It is expected that when you handle an expose event, you will just redraw everything. But if you have a very complicated image, this is a slow process, especially in Python. So it would be much nicer if Cairo could write to a permanent double buffer rather than a temporary one, and then that permanent double buffer would be exposed with GDK. Several developers have wanted a solution to this problem. One of the projects that seems to have some kind of solution is Google Chromium --- have you ever noticed how great window exposure is in Google Chrome, for instance in Linux? So I will look at the Chromium source code to see if I can do this easily.
Addendum: I see that I did confuse the issue by referring specifically to "pixbufs". I don't really care about pixbufs (and I changed the question title again). What I really care about is creating a permanent double buffer pixel array between Cairo and GTK/GDK, instead of a temporary double buffer pixel array. It seems that the easiest way to do that is to make the GTK window a Cairo surface and make the double buffer another Cairo surface. Since I asked for an sample in my question, here is some:
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()
Another tricky issue that quickly arose is that I wanted this to be a WYSISWYG drawing environment that immediately draws what Python asks it to draw --- and that can be extended to animations. However, most GTK examples aren't set up that way: event handling is postponed until I either call gtk.main()
. (Or in Python, I was surprised to discover that raw_input()
also somehow flushes the GTK event queue.) I found a nice explanation, with Python examples, of alternatives to giving away event control to GTK. The simplest solution and possibly the one that I will adopt is to use this to flush the event buffer whenever you want to do that:
while gtk.events_pending(): gtk.main_iteration(False)
There is one final thing that I will need, to flush the pixel buffer as well as the event buffer. It looks like one way to do that is window.queue_draw()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于这对于评论来说太大了,我已将其添加为回复。
问题不太清楚。您的意思是问如何使用 cairo 绘图在 Gtk Widgets 上绘图吗?首先,没有什么叫GTK Pixbuf,我想你指的是GDK Pixbuf。 GTK 中的大部分绘图工作都是在 GDK 层完成的。如果您想了解窗口、绘图机制或图像操作,您应该查看 GDK 以获取更多详细信息。 这些 链接 希望能帮助您深入了解 cairo-gdk 交互。虽然我对 GTK、GDK 和 Python 绑定的经验很丰富。 Cairo 是零,但我认为如果您查找 gdk-cairo 示例,Google 将为您提供一些好的资源。
希望这至少有一点帮助!
As this was too big for a comment I have added this as a response.
The question is not quite clear. Do you mean to ask how to use cairo drawing to draw onto Gtk Widgets? Firstly, there is nothing called GTK Pixbuf, I think you are referring to GDK Pixbuf. Most the drawing stuff in GTK is done at GDK layer. If you want to find out about windowing, drawing mechanism or image manipulation you should look into GDK for more details. These links will hopefully help you get some insight about cairo-gdk interaction. Although my experience with python bindings for GTK, GDK & Cairo is nil, but I think that Google will provide you with some good resources if you look up gdk-cairo sample.
Hope this helps at least a bit!