Каирский контекст и постоянство? - PullRequest
3 голосов
/ 18 августа 2010

Я только начинаю использовать pycairo и столкнулся со следующей интересной ошибкой. Программа, которую я пишу, создает простое окно gtk, рисует на нем прямоугольник, а затем имеет функцию обратного вызова для рисования случайной линии на любом виде ввода с клавиатуры. Однако, похоже, что при каждом вводе с клавиатуры мне приходится создавать новый контекст, или я получаю сообщение об ошибке в тот момент, когда программа получает первый ввод с клавиатуры (в частности, в строке .stroke ()). Ошибка заключается в следующем, если это имеет значение. 'BadDrawable (неверный параметр Pixmap или Window)'. (Подробности: серийный номер 230, код ошибки 9, код запроса 53, младший код 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)

Спасибо за вашу помощь!

(Обновление: я играл, и я понял следующее: когда я изменяю размер окна, все добавленные новые объекты удаляются (или, по крайней мере, больше не появляются?))

Ответы [ 3 ]

2 голосов
/ 19 августа 2010

Каирские рисунки не сохраняются вообще.(Лучше не думать о них как об «объектах» - это не библиотека холстов, где вы можете перемещать их или преобразовывать их после того, как вы их нарисовали.) Вы должны сделать все рисование в обработчике экспозиции, иликак вы выяснили, исчезнет всякий раз, когда окно перерисовывается.

Контекст cairo не сохраняется из-за двойной буферизации: см. примечание в документации по C , которое, к сожалению, яне удалось найти нигде в документации PyGTK.

В приведенном выше коде вы должны сгенерировать координаты и цвет произвольной линии в обработчике нажатия клавиш и сохранить их в массиве.Затем в обработчике экспозиции нарисуйте каждую строку в массиве по порядку.

1 голос
/ 26 сентября 2010

, в то время как вам нужно создавать контекст при каждом запуске, вы можете добиться требуемой стойкости, отключив двойную буферизацию виджета.

вот пример использования графической библиотеки хомяка, которая просто делает это:

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

0 голосов
/ 01 октября 2010

Много вариантов настойчивости для обсуждения:

Рисунки на некоторых поверхностях не сохраняются: поверхности с графическим интерфейсом.Вы должны перерисовать их в обратном вызове expose.

Объекты PyCairo не должны рассматриваться как постоянные объекты, только как интерфейс к функциям библиотеки Cairo в C.

Содержимое (пути иЗаполнение) Cairo контексты не сохраняются за пределами операции stroke () или fill ().

Контекст для поверхности GUI не сохраняется между событиями выставления (из-за двойной буферизации?) (я неНе знаю, сохраняется ли контекст для других поверхностей, например устройств.) Таким образом, вы не можете использовать контекст cairo для хранения атрибутов области просмотра (окна в документе, то есть модели в пользовательских координатах.)

Визуальное сохранениеэто тенденция человеческого глаза видеть свет после того, как он прекратился.Призраки и мерцание - это его симптомы в анимации или видео.Отключение двойной буферизации позволяет вам видеть вещи в том виде, в котором они нарисованы, то есть включать анимацию в рамках одного события экспозиции (симуляция симптомов визуальной персистенции). Отключение двойной буферизации не делает контекст на поверхности графического интерфейса постоянным между событиями экспозиции.

Постоянство памяти - это ваша настоящая настойчивость, или, я бы сказал, сюрреалистическая.

...