Search code examples
pythonwxpythonpython-multithreadingpypubsub

Python: Does PubSub and WxPython with Threading require wx.CallAfter?


I am using:

wxPython 4.0.7.post2

Pypubsub 4.0.3

Python 3.8.1

I have the following example program I have written:

import wx
import time
from threading import Thread
from pubsub import pub

TIME_UPDATED = "time.updated"


class MyFrame(wx.Frame):

    def __init__(self):
        super().__init__(parent=None, title="Example")
        self.text = wx.StaticText(self, label="I will display seconds elapsed!")
        self.othertext = wx.StaticText(self, label="I will Update")

        sizer = wx.BoxSizer(orient=wx.VERTICAL)
        sizer.Add(self.text)
        sizer.Add(self.othertext)
        self.SetSizer(sizer)

        self.timer = wx.Timer(self)
        pub.subscribe(self.UpdateTime, TIME_UPDATED)
        self.Bind(wx.EVT_TIMER, self.OnTime, self.timer)
        self.Show()

        self.i = 0
        self.timer.Start(500)

    def OnTime(self, _):
        self.i += 1
        self.othertext.SetLabel(str(self.i))

    def UpdateTime(self, seconds):
        self.text.SetLabel("{seconds} seconds have elapsed".format(seconds=seconds))
        self.text.Refresh()


class BackgroundThread(Thread):

    def run(self):
        time_elapsed = 0
        while True:
            # Lets sleep 1 second
            time.sleep(1)
            time_elapsed += 1
            # <<<<---- This line is what I am worried about.
            pub.sendMessage(TIME_UPDATED, seconds=time_elapsed)


if __name__ == '__main__':

    app = wx.App()
    frame = MyFrame()

    background = BackgroundThread(daemon=True)
    background.start()

    app.MainLoop()

I am performing a pub.sendMessage(TIME_UPDATED, seconds=time_elapsed) without a wx.CallAfter and it seems to be working fine. I am not sure why.

Could someone please explain if wx.CallAfter is necessary anymore?

If it is can you explain why that is? Is it that some wx methods put something onto the dispatch queue whereas others do not?


Solution

  • Yes, you should still ensure that UI operations occur on the UI thread. Just because something is not safe to do does not mean that it doesn't happen to work okay (or apprear to work okay) in some cases.