[pygtk] Signal Blocking
Shandy Brown
sjbrown at vmware.com
Fri Nov 30 05:04:34 WST 2007
I found the error. I was trying to block the signal on the wrong
widget. This change fixes it:
#-----------------------------------------------------------------------------
def SignalLoopProtected( widgetName, signalName ):
'''This decorator ensures that a loop won't be created from a callback
continually calling itself in a loop, or a loop between a pair of callbacks
that call each other. It takes the callback, "origFunc" and wraps it
in calls to handler_block and handler_unblock.
Requirements:
a handler ID has to be created and stored in the instance. It has to be
accessible by calling GetHandlerID(widgetName, signalName)
'''
def Decorated( origFunc ):
def NewFunc( self, widget, *args ):
assert hasattr(widget, 'handler_block') \
and hasattr(self,'GetHandlerID'), \
'SignalLoopProtected can only decorate GTK callback funcs that'+\
' can be retrieved from self.GetHandlerID(widgetName,signalName)'
foreignWidget, handlerID = self.GetHandlerID(widgetName, signalName)
print "++ Blocking signal %s id: %d" % (signalName, handlerID)
foreignWidget.handler_block( handlerID )
rc = origFunc( self, widget, *args )
print '-- Unblocking signal %s id: %d' % (signalName, handlerID)
foreignWidget.handler_unblock( handlerID )
return rc
NewFunc.func_name = origFunc.func_name
return NewFunc
return Decorated
#-----------------------------------------------------------------------------
class GladeInspectingAutoconnecter(object):
'''Base class that inspects Glade XML and autoconnects
matching names to the instance
Provides Autoconnect(), which should be called at the end of __init__,
and GetHandlerID, which is useful for the above decorator,
SignalLoopProtected.
'''
# Regular expression to match handler method names patterns
# On_widget__signal and After_widget__signal. Note that we use two
# underscores between the Glade widget name and the signal name.
handler_re = re.compile(r'(On|After)_(.*)__(.*)', re.IGNORECASE)
def Autoconnect(self, xml):
"""Connects signal handling methods to Glade widgets.
Methods named like On_widget__signal or After_widget__signal
are connected to the appropriate widgets and signals.
"""
self._handlerIDs = {}
for attr in dir(self):
match = self.handler_re.match(attr)
if not match:
continue
when, widgetName, signalName = match.groups()
method = getattr(self, attr)
assert callable(method), 'Instance attr looks like method name'
widget = xml.get_widget(widgetName)
if not widget:
continue
handlerID = widget.connect(signalName.replace('_', '-'), method)
self._handlerIDs[(widgetName, signalName)] = (widget, handlerID)
print 'All handlers found:'
for k,v in self._handlerIDs.items():
print "%40s : %5s" % (k,v)
def GetHandlerID( self, widgetName, signalName ):
return self._handlerIDs[(widgetName, signalName)]
On Wed, 2007-11-28 at 11:34 -0800, Shandy Brown wrote:
> I didn't get a response to this question regarding the right way to
> block a signal. I have reworked my example to be much much smaller so
> that hopefully it garners some eyeballs.
>
> Again, if my approach is fundamentally wrong, please let me know.
>
> To reiterate the problem: I basically want two widgets to affect each
> other's values. But if I do this naievely, like so...
>
> Spinbutton
> on_value_changed:
> Entry.set_text()
> Entry
> on_changed:
> Spinbutton.set_value()
>
> That causes an infinite loop. My idea is to block the signals before
> calling set_text() or set_value(), but, as the attached example will
> show, I get an error (min_clock.py:29: Warning: gsignal.c:1695: instance
> `0xb25840' has no handler with id `46')
>
> Any guidance would be appreciated.
>
> Shandy
>
> On Tue, 2007-11-20 at 11:03 -0800, Shandy Brown wrote:
> > I'm trying to write a clock widget. I want it to look nice and to
> > behave in a friendly manner.
> >
> > * It should show colons between the hours, minutes, and seconds
> > * typing the time should "skip" over the colons
> >
> > I've tried to implement this by 5 sequential text entry widgets, each
> > without a frame so they look like they're part of the same widget, laid
> > out like this:
> >
> > +----+---+----+---+----+
> > | hh | : | mm | : | ss |
> > +----+---+----+---+----+
> >
> > if the time is 10:20, I want focus to default to the hours, and the user
> > can type in "1020".
> >
> > The best way I can think of doing this is by detecting that on the
> > keypress for "2", the number is out of bounds, then blocking the signals
> > for the minute text entry, and setting it's value to 2.
> >
> > However, sometimes when I try to block the signals, I get the message
> >
> > Warning: gsignal.c:1695: instance `0xaf6800' has no handler with id `115'
> >
> > Which doesn't make sense to me, because I 115 definitely exists, as I
> > stored it previously.
> >
> > I've attached the code which will exhibit the behaviour. Just type
> > "python clock.py"
> >
> > Any suggestions? Anyone know why signal 115 disappears?
> >
> > -sjbrown
> > _______________________________________________
> > pygtk mailing list pygtk at daa.com.au
> > http://www.daa.com.au/mailman/listinfo/pygtk
> > Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
> _______________________________________________
> pygtk mailing list pygtk at daa.com.au
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
More information about the pygtk
mailing list