【问题标题】:Cairo context and persistence?开罗背景和持久性?
【发布时间】:2010-08-18 14:32:07
【问题描述】:

我刚开始使用 pycairo,遇到了以下有趣的错误。我编写的程序创建一个简单的 gtk 窗口,在其上绘制一个矩形,然后有一个回调在任何类型的键盘输入上绘制一条随机线。但是,似乎对于每个键盘输入,我都必须创建一个新的上下文,或者在程序接收到第一个键盘输入时出现错误(特别是在 .stroke() 行上)。错误如下,如果重要的话。 'BadDrawable(无效的像素图或窗口参数)'。 (详情: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)

感谢您的帮助!

(更新:我在玩,我意识到以下几点:当我调整窗口大小时,所有添加的新对象都会被删除(或者至少不再出现?)

【问题讨论】:

标签: python gtk pygtk cairo pycairo


【解决方案1】:

开罗图纸根本不存在。 (最好不要将它们视为“对象”——它不像画布库,您可以在其中移动它们或在绘制它们之后对其进行转换。)您必须在暴露处理程序中完成所有绘制,或者它正如您所发现的,每当重绘窗口时,它就会消失。

由于双缓冲,cairo 上下文不会持续存在:请参阅note in the C documentation,不幸的是我在 PyGTK 文档中的任何地方都找不到。

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

【讨论】:

  • 在解决这个问题后,我意识到这可能类似于画布的想法。感谢您填补有关 cairo 工作方式的空白。我想我对画布隐喻的重视不够。
  • 小记:是 GTK 做的。开罗本身与坚持无关。对于 GTK,expose 事件意味着“不知道该区域过去是什么,请重新绘制所有区域”。
【解决方案2】:

虽然您必须在每次运行时创建上下文,但您可以通过禁用小部件的双缓冲来实现所需的持久性。

这是一个使用仓鼠图形库的示例:

https://github.com/projecthamster/experiments/blob/master/many_lines.py

【讨论】:

    【解决方案3】:

    要讨论的许多坚持:

    一些表面上的绘图不会持续存在:GUI 表面。你应该在暴露回调中重绘它们。

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

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

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

    视觉持久性是人眼在光线停止后看到光线的趋势。鬼和闪烁是它在动画或视频中的症状。禁用双缓冲可以让您在绘制时看到它们,也就是说,在一个公开事件中启用动画(模拟视觉持久性的症状)。禁用双缓冲不会使 GUI 表面上的上下文在公开事件之间保持持久。

    记忆的持久是你真正的持久,或者说是超现实的。

    【讨论】:

      猜你喜欢
      • 2012-11-08
      • 1970-01-01
      • 1970-01-01
      • 2017-01-15
      • 2011-10-18
      • 1970-01-01
      • 1970-01-01
      • 2013-07-17
      • 1970-01-01
      相关资源
      最近更新 更多