开罗上下文和持久性?

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/感兴趣 - 它在Cairo之上提供了一个相当有帮助的抽象。即使你不使用完整的库,其中提供的缓动函数也值得一看。 - Donald Harvey
3个回答

2
开罗图形根本不会持久存在。(最好不要将它们看作“对象”——这不像画布库,你可以在绘制后移动或转换它们。)你必须在曝光处理程序中完成所有的绘图,否则,就像你发现的那样,每当窗口重新绘制时,它就会消失。

cairo上下文不会持久存在,因为存在双缓冲:请参见C文档中的注释,不幸的是我在PyGTK文档中找不到它。

在上面的代码中,你应该在按键处理程序中生成随机线条的坐标和颜色,并将它们保存在数组中。然后在曝光处理程序中,按顺序绘制数组中的每条线。


经过一夜的思考,我意识到这个问题可能与画布的概念类似。感谢您填补了我对cairo工作方式的空白。我想我没有认真对待画布的隐喻。 - Kurt Spindler
小注:这是GTK的功能。Cairo本身与持久性无关。对于GTK来说,暴露事件意味着“不知道之前在这个区域上有什么,请重新绘制所有内容”。 - Uli Schlachter

1

0

讨论多种持久性的变化:

在一些表面上绘制的内容不会持久存在:GUI 表面。您应该在 expose 回调中重新绘制它们。

PyCairo 对象不应被视为持久对象,而只是 C 中 Cairo 库函数的接口。

Cairo 上下文的内容(路径和填充)在 stroke() 或 fill() 操作之后不会持久存在。

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

视觉持久性是人眼看到光线停止后仍然能够看到的倾向。幽灵和闪烁是动画或视频中的症状。禁用双缓冲可以让您看到绘制的东西,也就是在一个 expose 事件中启用动画(模拟视觉持久性的症状)。禁用双缓冲不会使 GUI 表面上的上下文在 expose 事件之间持久存在。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接