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
- wxPython and PubSub: A Simple Tutorial
- One of the many threads on pubsub on the wxPython mailing list
- The pubsub website
- wxPython: How to Update a Progress Bar from a Thread
Hi Mike,
As always a very nice tutorial.
I too use pubsub for some time now, when I switched to the new API I also started to use a predefined topic tree.
That requires a bit more setup but you don’t have problems because you misspell a topic and you get code completion for topic names and your topics are documented in one place.
Maybe another tutorial:)
Pingback: Mike Driscoll: wxPython: Using PyDispatcher instead of Pubsub | The Black Velvet Room
Pingback: Enable a button in the parent wx.Frame – PythonCharm
Pingback: wxPython 4 and PubSub | The Mouse Vs. The Python
Pingback: wxPython: How to Communicate with Your GUI via sockets - The Mouse Vs. The Python