2010-08-18 67 views
3

我刚开始使用pycairo,并遇到以下有趣的错误。我编写的程序创建一个简单的gtk窗口,在其上绘制一个矩形,然后有一个回调在任何类型的键盘输入上绘制一条随机线。但是,似乎每个键盘输入都必须创建一个新的上下文,否则在程序收到第一个键盘输入(特别是在.stroke()行)时出现错误。错误如下,如果重要。 'BadDrawable(无效的Pixmap或Window参数)'。 (详情:serial 230 error_code 9 request_code 53 minor_code 0)开罗上下文和持久性?

#! /usr/bin/env python 
import pygtk 
pygtk.require('2.0') 
import gtk, gobject, cairo, math, random 
# Create a GTK+ widget on which we will draw using Cairo 
class Screen(gtk.DrawingArea): 
# Draw in response to an expose-event 
    __gsignals__ = { "expose-event": "override" } 

    # Handle the expose-event by drawing 
    def do_expose_event(self, event): 
    # Create the cairo context 
    self.cr = self.window.cairo_create() 
    # Restrict Cairo to the exposed area; avoid extra work 
    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 key_press_event(self, *args): 
    # print args 
    self.cr = self.window.cairo_create() # This is the line I have to add 
    # in order to make this function not throw the error. Note that cr is only 
    # given as attribute of self in order to stop it going out of scope when this line 
    # doesn't exist 
    self.cr.set_source_rgb(random.random(), random.random(), random.random()) 
    self.cr.move_to(*[z/2.0 for z in self.window.get_size()]) 
    self.cr.line_to(*[z*random.random() for z in self.window.get_size()]) 
    self.cr.stroke() 

    def draw(self, width, height): 
    # Fill the background with gray 
    self.cr.set_source_rgb(.5,.5,.5) 
    self.cr.rectangle(0, 0, width,height) 
    self.cr.fill() 

    self.cr.set_source_rgb(1,0,0) 
    self.cr.arc(width/2.0, height/2.0, min(width,height)/2.0 - 20.0, 0.0, 2.0*math.pi) 
    self.cr.stroke() 

#create a gtk window, attach to exit button, and whatever is passed as arg becomes the body of the window. AWESOME 
def run(Widget): 
    window = gtk.Window() 
    widget = Widget() 
    window.connect("delete-event", gtk.main_quit) 
    window.connect('key-press-event',widget.key_press_event) 
    widget.show() 
    window.add(widget) 
    window.present() 
    gtk.main() 

if __name__ == "__main__": 
    run(Screen) 

感谢您的帮助!

(更新:我打过来,我实现了以下内容:当我调整窗口的大小,添加的所有新对象被删除(或者至少不会再出现)?)

+1

您可能对http://wiki.github.com/tbaugis/hamster_experiments/感兴趣 - 它在开罗之上提供了一个相当有用的抽象。即使你不使用完整的库,包含的tweener当然值得关注。 – 2010-08-19 12:41:13

回答

2

开罗图纸不要坚持。 (最好不要将它们视为“对象” - 它不像一个画布库,在绘制它们之后可以移动它们或将它们转换)。必须在曝光处理程序中执行所有绘制,或者它就像你发现的那样,只要窗口重新绘制就会消失。

由于双缓冲,cairo上下文不会持续:请参阅note in the C documentation,很遗憾,在PyGTK文档中找不到任何地方。

在上面的代码中,您应该在按键处理程序中生成随机行的坐标和颜色,并将它们保存在数组中。然后在公开处理程序中,依次绘制数组中的每一行。

+0

沉睡之后,我意识到这可能是类似于画布的想法。感谢您填补开罗工作方式的空白。我想我没有认真对待帆布比喻。 – 2010-08-19 16:08:43

0

许多持久的口味来讨论:

图纸上一些表面不坚持:GUI表面。你应该在揭露回调中重新绘制它们。

PyCairo对象不应该被视为持久对象,仅作为接口开罗库的函数C.

开罗上下文的内容(路径和填充)不会持续超过行程( )或fill()操作。

一个GUI表面的上下文不会在公开事件之间持续存在(因为双缓冲?)(我不知道上下文是否持续存在于其他表面上,即设备)。因此,您不能使用cairo上下文以存储视口的属性(窗口到文档上,即用户坐标系中的模型)。

视觉持久性是人眼在光线停止后看到光线的倾向。幽灵和闪烁是动画或视频中的症状。禁用双缓冲可让您在绘制事件时看到事物,即在一个公开事件中启用动画(模拟可视持久性的症状)。禁用双缓冲不会使暴露事件之间的GUI表面上的持续上下文保持不变。

记忆的持久性是你真正的持久性,或者我应该说超现实主义。