Question

This may seem a bit general, but the problem is quite simple actually. Is it possible to subscribe to a subset of topics using the pubsub module.

Let me briefly explain what I would like to accomplish. In a wxpython project I want to change the text in the status bar according to different events. So I would like to have one function (one listener) which would subscribe to a set of topics. In the listener I would have if statement and several elif statements where the topic's name would be checked. Then the status bar text would be changed accordingly.

Is it possible to do this, or is it a bad idea in the first place. How should I deal with that kind of situation. Thanks in advance

Was it helpful?

Solution 2

There are a couple of approaches. First and perhaps simplest, you could have just one listener. When you publish to the listener, you just pass it different pieces of information. For example, from class A, you would pass one string. For class B, you might pass a different string, but to the same listener. Then in the listener, you just check for which string, as you mentioned.

The other approach would be to create multiple listeners that are all bound to the same function or method. Then you can publish to the different listeners and they will all call the same thing.

You should use the approach that you find easiest to understand and debug.

Here's an example:

import wx
from wx.lib.pubsub import pub 

########################################################################
class OtherFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, wx.ID_ANY, "Secondary Frame")
        panel = wx.Panel(self)

        msg = "Enter a Message to send to the main frame"
        instructions = wx.StaticText(panel, label=msg)
        self.msgTxt = wx.TextCtrl(panel, value="")

        sendBtn = wx.Button(panel, label="Send Msg")
        sendBtn.Bind(wx.EVT_BUTTON, self.onSendMsg)

        closeBtn = wx.Button(panel, label="Send and Close")
        closeBtn.Bind(wx.EVT_BUTTON, self.onSendAndClose)

        sizer = wx.BoxSizer(wx.VERTICAL)
        flags = wx.ALL|wx.CENTER
        sizer.Add(instructions, 0, flags, 5)
        sizer.Add(self.msgTxt, 0, flags, 5)
        sizer.Add(sendBtn, 0, flags, 5)
        sizer.Add(closeBtn, 0, flags, 5)
        panel.SetSizer(sizer)

    #----------------------------------------------------------------------
    def onSendMsg(self, event):
        """"""
        msg = "Another message!"
        pub.sendMessage("anotherListener", 
                        message=msg,
                        listener="anotherListener")

    #----------------------------------------------------------------------
    def onSendAndClose(self, event):
        """
        Send a message and close frame
        """
        msg = self.msgTxt.GetValue()
        pub.sendMessage("panelListener", 
                        message=msg,
                        listener="panelListener")
        self.Close()

########################################################################
class MyPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        pub.subscribe(self.myListener, "panelListener")
        pub.subscribe(self.myListener, "anotherListener")

        btn = wx.Button(self, label="Open Frame")
        btn.Bind(wx.EVT_BUTTON, self.onOpenFrame)

    #----------------------------------------------------------------------
    def myListener(self, message, listener=None):
        """
        Listener function
        """

        if listener == "panelListener":
            print "panel listener has sent the following: ",
            print message
        elif listener == "anotherListener":
            print "another listener sent the following: ", 
            print message

    #----------------------------------------------------------------------
    def onOpenFrame(self, event):
        """
        Opens secondary frame
        """
        frame = OtherFrame()
        frame.Show()

########################################################################
class MyFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="New PubSub API Tutorial")
        panel = MyPanel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

This is a modified example from my tutorial: http://www.blog.pythonlibrary.org/2013/09/05/wxpython-2-9-and-the-newer-pubsub-api-a-simple-tutorial/

OTHER TIPS

It is a bad idea in the first place. You should let pubsub do the work for you. One listener per topic. There is no cost to doing that, it segregates your code, makes it easier to maintain, separation of responsibilities.

That said, a listener can listen to base topic: pub.subscribe('a.b', listener) will get messages for topic a.b, a.b.c, a.b.d, a.b.c.e, etc. As described in the pubsub docs, you can tell pusub to give the topic object as part of message by using a keyword arg that has a default value of pub.AUTO_TOPIC. But if you use this strategy and you end up with a long list of if/elif/else its probably not the way to go.

Perhaps if you give more details about the topic hierarchy you intend to have, and the kind of if/else you had in mind, I can provide more useful feedback.

Another approach is to call pub.subscribe, multiple times, for the same subscriber function but with different specific subtopics. For example say you have an email spam filter that classifies spam into 20 different specific categories that can be grouped into five groups. At this time you only want to handle two groups of those categories. Here is a way:

def delete_spam_subscriber(header, message):
   delete_message(header, message)

def junkmail_subscriber(header, message):
   move_to_junk(header, message)

pub.subscribe(delete_spam_subscriber, 'root.spam.profanity')
pub.subscribe(delete_spam_subscriber, 'root.spam.spyware')
pub.subscribe(delete_spam_subscriber, 'root.spam.indirect')

pub.subscribe(junkmail_subscriber, 'root.spam.unknown_sender')
pub.subscribe(junkmail_subscriber, 'root.spam.forum_replys')
pub.subscribe(junkmail_subscriber, 'root.spam.receive_but_limit')

This is of course if you don't want to create by grouping topics 'root.spam.deletables', 'root.spam.to_junk_folder'

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top