wxPython 2.9 and the Newer Pubsub API: A Simple Tutorial

NOTE: This article is for wxPython 2.9-3.0. If you are using wxPython 4, you should go to my newer article

Several years ago, I wrote a tutorial about wxPython 2.8 and its built-in pubsub module which you can read here. Back then, a new API for pubsub was added in wxPython 2.8.11.0 that could be enabled by doing the following:

import wx.lib.pubsub.setupkwargs
from wx.lib.pubsub import pub

The old way of importing pubsub was to do the following:

from wx.lib.pubsub import Publisher

Now in wxPython 2.9, it has changed to this:

from wx.lib.pubsub import pub

Thus you cannot use the code in my old tutorial any more and expect it to work in the latest version of wxPython. So it's time to update the tutorial a bit.

The new pubsub API

Let's take the original code from the old article and spruce it up using pubsub's newer API. It won't take very long. In fact, it's a very minor code change. Let's take a look!

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="")
        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(closeBtn, 0, flags, 5)
        panel.SetSizer(sizer)
 
    #----------------------------------------------------------------------
    def onSendAndClose(self, event):
        """
        Send a message and close frame
        """
        msg = self.msgTxt.GetValue()
        pub.sendMessage("panelListener", message=msg)
        pub.sendMessage("panelListener", message="test2", arg2="2nd argument!")
        self.Close()

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

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        pub.subscribe(self.myListener, "panelListener")
        
        btn = wx.Button(self, label="Open Frame")
        btn.Bind(wx.EVT_BUTTON, self.onOpenFrame)
        
    #----------------------------------------------------------------------
    def myListener(self, message, arg2=None):
        """
        Listener function
        """
        print "Received the following message: " + message
        if arg2:
            print "Received another arguments: " + str(arg2)
            
    #----------------------------------------------------------------------
    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()

As we have already discussed, the import is different. Let's see what else has changed. In the panel class, we create a listener like this:

pub.subscribe(self.myListener, "panelListener")

The myListener method can accept one or more arguments. In this case, we set it up to always require one argument (message) and an optional argument (arg2). Next we turn to the OtherFrame class where we need to take a look at the onSendAndClose method. In this method, we find that it sends out two messages:

msg = self.msgTxt.GetValue()
pub.sendMessage("panelListener", message=msg)
pub.sendMessage("panelListener", message="test2", arg2="2nd argument!")
self.Close()

The first one just sends the required information whereas the second one sends both. You will note that the new API requires the use of explicit keyword arguments. If you change the first sendMessage command to pub.sendMessage("panelListener", msg), you will receive a TypeError exception.

Wrapping Up

That was a pretty simple change, eh? I think the new pubsub API is actually more readable and a little less "magical" than the original. Hopefully you will too. Have fun and happy coding!

Additional Reading

Copyright © 2024 Mouse Vs Python | Powered by Pythonlibrary