Cairo context and perseverance?

I am just starting to use pycairo, and I came across the following interesting error. The program I am writing creates a simple gtk window, draws a rectangle on it and then has a callback to draw a random line on any keyboard input. However, it seems that with each input on the keyboard I need to create a new context, or I get an error when the program receives the first input on the keyboard (in particular, in the .stroke () line). The error is as follows, if that matters. 'BadDrawable (invalid Pixmap or Window parameter)'. (Details: 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)

Thank you for your help!

(: , : , , , (, , ?))

+3
4

. ( "" - , , .) , , , , .

cairo - : . C, , - PyGTK.

. .

+2

:

: . .

PyCairo , Cairo C.

( ) stroke() fill().

GUI (- ?) ( , , .. .) , cairo ( , .)

- . - . , ( ). .

- , , .

0

?

#! /usr/bin/env python
import pygtk
pygtk.require('2.0')
from gtk import gdk
import gtk, gobject, cairo, math, random
from itertools import izip as abrakadabra
# Create a GTK+ widget on which we will draw using Cairo

class Lines(gtk.DrawingArea):
# Draw in response to an expose-event

     def __init__(self):
        gtk.DrawingArea.__init__(self)
        self.connect("expose_event", self.expose)
        #self.connect("key_release_event",self.on_key_press) ### works opposite
        self.connect("key_press_event", self.on_key_press)
        self.add_events( gdk.KEY_PRESS_MASK )
        self.set_flags(gtk.CAN_FOCUS)
        gobject.timeout_add(20, self.on_timeout)
        self.pressed = None
        self.middle_P = [0,0]
        self.lines = [[0,0]]
        self.RGB = [[0,0,0]]
        self.n_line = [0,0]
        self.n_RGB = [0,0,0]
        self.ref =[0,0]


     def expose(self, widget, event):
        self.cr = widget.window.cairo_create()
        self.cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
        self.draw(*self.window.get_size())
        return False


     def on_key_press ( self, widget, event ):
        self.pressed = event.string
        if self.pressed != None:
            self.n_line = [z*random.random() for z in self.window.get_size()]
            self.lines.append( self.n_line)
            self.n_RGB = [random.random(), random.random(), random.random()]
            self.RGB.append(self.n_RGB)
            self.pressed = None


     def on_timeout(self):
        if self.middle_P != self.ref: ### check if the window is the same size as on previous timeout
            self.move_lanes()
        self.middle_P = [z/2.0 for z in self.window.get_size()]
        win = self.get_window()
        rect = self.get_allocation()
        win.invalidate_rect(rect, False)
        return True


     def move_lanes(self):  
         for i in range(0, len(self.lines)):
            diff = [xy_p - xy_n for xy_p, xy_n in abrakadabra(self.ref, self.middle_P)] ### first -> draw func xy_p and second -> timeout func xy_n coordinate to get size difference on demand (checking every 20ms)
            self.lines[i] = [m_xy + sh_diff for m_xy, sh_diff in abrakadabra(self.lines[i], diff)] ### m_xy many xy points to draw many lines , sh_diff  "shared" windows size diff (const difference for each lines)
            ### //abrakadabra -> itertools.izip




     def draw(self, width, height):
        self.ref = [(width)/2.0,(height)/2.0] ### get half of actuall win size to obtain difference during resizing
        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()


        for i in range(1, len(self.lines)): ### can start from 0 but no need
            #self.cr.set_source_rgb(self.RGB[i][0], self.RGB[i][1], self.RGB[i][2])    ### mark when running nice effects
            self.cr.set_source_rgb(random.random(), random.random(), random.random()) ### unmark for nice effects but mark previus line first
            self.cr.move_to(self.middle_P[0], self.middle_P[1])
            self.cr.line_to(self.lines[i][0], self.lines[i][1])
            self.cr.stroke()



def run(Widget):
    window = gtk.Window()
    widget = Widget()
    window.connect("delete-event", gtk.main_quit)
    window.add(widget)
    window.show_all()
    gtk.main()

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

I'm still learning and I would like to know if there is an even more Pythonic way to achieve the same functionality? I mean moving / converting strings continuously unchanged in size while the window is being resized? In addition, I did not see any differences between the built-in zip and itertools.izip in performance, how can I check the time and memory usage of each of these functions?

0
source

Source: https://habr.com/ru/post/1760320/


All Articles