"Jorgen Bodde" <jorgen.maillist@gmail.com> wrote:
> I am using pydispatcher to notify from a OnSelected() event in a
> wxListCtrl to an object that manages the list of items, which will
> then emit a signal to update all listeners.
>
> However, the signal does not want to send inside the event hander!
> When I send it in the main frame the signal is properly sent, but from
> the OnSelected contect in wxPython, it is not.
I've heard about it not working in some cases. I don't know why.
> Also, I read more about wx.lib.pubsub, is this one more robust against
> these oddities? I like to have the one that is most robust in the
> situation I described ..
wx.lib.pubsub looks complicated, but aside from using weakrefs to make
sure that your 'event subscriptions' don't keep an object alive which
should otherwise be garbage collected, it is more or less equivalent to...
callbacks = {}
def subscribe(fcn, topic=''):
topic = tuple(topic.split('.'))
callbacks.setdefault(topic, ).append(fcn)
def sendMessage(topic, data):
topic = tuple(topic.split('.'))
for i in xrange(len(topic)+1):
for j in callbacks.get(topic[:i]):
j(topic[:i], data)
That is to say, when you use
wx.lib.pubsub.Publisher.sendMessage(topic, data)
Every function that is called is called *immediately*, one right after
the other. This can cause not insignificant issues with certain event
interactions, and may violate certain expectations that you or the GUI
may or may not have (especially if you are using threads).
If you find that using pubsub is breaking certain expectations that you
have, you could wrap all of your calls via wx.CallAfter. For example,
say that you have a function 'foo' that you want to call when a topic is
sent a message...
#normally
wx.lib.pubsub.Publisher.subscribe(foo, topic)
#with wx.CallAfter
cb = lambda *args, foo=foo : wx.CallAfter(foo, *args)
You could write a subscribe function that does this for you, but it
would negate all the work that pubsub goes to in order to allow for dead
objects to die. You could also patch the base _TopicTreeNode to do use
wx.CallAfter always...
def sendMessage(self, message):
"""Send a message to our callables"""
deliveryCount = 0
for cb in self.__callables:
listener = cb()
if listener is not None:
wx.CallAfter(listener, message)
deliveryCount += 1
return deliveryCount
wx.lib.pubsub._TopicTreeNode.sendMessage = sendMessage
And this would behave very similarly to what you are currently doing,
except that it should always work.
- Josiah