SwapOff

Python hacking, redux. 
« Back to blog

Simplifying PyGTK signals in Python

This is a followup to my previous post.

A fairly common pattern in GTK code seems to be updating a widget whenever a value changes in your controller. That is, something like this:

class Counter(gobject.Gobject):
  __gsignals__ = {
    'counter-changed': (gobject.SIGNAL_RUN_FIRST,
                        gobject.TYPE_NONE, (int,)),
    }

  def __init__(self):
    self.counter = 0

  def inc(self):
    self.counter += 1
    self.emit('counter-changed', self.counter)

  def dec(self):
    self.counter -= 1
    self.emit('counter-changed', self.counter)


Needless to say, this can get a bit tedious. With a bit of stack frame hackery we can reduce that boilerplate to the following:

class Counter(gobject.GObject):
  counter = SignalProperty('counter-changed', 0)

  def inc(self):
    self.counter += 1

  def dec(self):
    self.counter -= 1


Here's the code:

class SignalProperty(object):
  def __init__(self, name, default=None):
    self.name =  name
    self.default = default
    frame = sys._getframe(1)
    locals_ = frame.f_locals
    signals = locals_.setdefault('__gsignals__', {})
    signals[name] = (gobject.SIGNAL_RUN_FIRST,
                     gobject.TYPE_NONE, (object,))

  def __get__(self, instance, owner):
    if instance is None:
      return self
    return getattr(instance, '_signal_' + self.name, self.default)

  def __set__(self, instance, value):
    setattr(instance, '_signal_' + self.name, value)
    instance.emit(self.name, value)



Loading mentions Retweet

Comments (0)

Leave a comment...

 
To leave a comment on this posterous, please login by clicking one of the following.
Posterous-login     Connect     twitter