Good approach for updating the GUI continuously in wxPython using threads?
Question: I am working on a GUI app using python v2.7 and wxPython v3.0 on windows 7 OS.
I have to update my GUI continuously which contains lots of panels. Each
panels contains a `wx.StaticText`. I have to update these `wx.StaticTexts`
continuously. I thought of using `threads`. Also I am using `pubsub` module
for communicating with the GUI to update these `wx.StaticTexts`. Every thing
works as intended. I have created a short demo below of my real problem.

**Problem** : In my code below, two threads are created. Both the threads are
able to update the GUI using `wx.CallAfter()`. What if I have 100 panels to
update? Do I need to create 100 classes for each of the thread which updates a
particular panel? I want the threads to work independently of the other
threads. What will possibly be the better approach than this one?

**Code** : Please find the sample code below to play around:

    
    
    import wx
    from wx.lib.pubsub import setupkwargs
    from wx.lib.pubsub import pub
    import time
    from threading import Thread
    import threading
    
    class GUI(wx.Frame):
        def __init__(self, parent, id, title):
            screenWidth = 500
            screenHeight = 400
            screenSize = (screenWidth,screenHeight)
            wx.Frame.__init__(self, None, id, title, size=screenSize)
            self.locationFont = locationFont = wx.Font(12, wx.MODERN, wx.NORMAL, wx.BOLD)
            mainSizer = wx.BoxSizer(wx.VERTICAL)
            myPanelA = wx.Panel(self, style=wx.SIMPLE_BORDER)
            myPanelA.SetBackgroundColour('#C0FAE0')
            self.myTextA = wx.StaticText(myPanelA, -1, "I have a problem :( ")
            myPanelB = wx.Panel(self, style=wx.SIMPLE_BORDER)
            myPanelB.SetBackgroundColour('#C0FAFF')
            self.myTextB = wx.StaticText(myPanelB, -1, "Me too :( ")
            mainSizer.Add(myPanelA, 1, wx.EXPAND, 5)
            mainSizer.Add(myPanelB, 1, wx.EXPAND, 5)
            self.SetSizer(mainSizer)
            pub.subscribe(self.updatePanelA, 'Update-panelA')
            pub.subscribe(self.updatePanelB, 'Update-panelB')
    
        def updatePanelA(self, message):
            self.myTextA.SetLabel(message)
    
        def updatePanelB(self, message):
            self.myTextB.SetLabel(message)
    
    class threadA(Thread):
        def __init__(self):
            Thread.__init__(self)
            self.start()
        def run(self):
            ObjA = updateGUI()
            ObjA.methodA()
    
    class threadB(Thread):
        def __init__(self):
            Thread.__init__(self)
            self.start()
        def run(self):
            ObjB = updateGUI()
            ObjB.methodB()
    
    class updateGUI():
        def methodA(self):
            while True:
                time.sleep(3)
                wx.CallAfter(pub.sendMessage, 'Update-panelA', message='Problem solved')
        def methodB(self):
            while True:
                time.sleep(5)
                wx.CallAfter(pub.sendMessage, 'Update-panelB', message='Mine too')
    
    if __name__=='__main__':
        app = wx.App()
        frame = GUI(parent=None, id=-1, title="Problem Demo")
        frame.Show()
        threadA()
        threadB()
        app.MainLoop()
    

Thank you for your time!


Answer: You can define your private "selfUpdatePanel" to launch its own thread to
update its own text field. The code would be easy maintain in this way.

Check following code modified based on your code:

    
    
    import wx
    from wx.lib.pubsub import setupkwargs
    from wx.lib.pubsub import pub
    import time
    from threading import Thread
    import threading
    
    
    class selfUpdatePanel(wx.Panel):
        def __init__(self, parent, mystyle, interval, topic, message):
            wx.Panel.__init__(self, parent, style = mystyle)
            pub.subscribe(self.updatePanel, topic)
            self.updateMsg = message
            self.textCtrl = None
            self.interval = interval
            self.topic = topic
            pub.subscribe(self.updatePanel, self.topic)
    
        def setTextCtrl(self,text):
            self.textCtrl = text
    
        def updatePanel(self):
            self.textCtrl.SetLabel(self.updateMsg)
    
        def threadMethod(self):
            while True:
                print "threadMethod"
                time.sleep(self.interval)
                wx.CallAfter(pub.sendMessage, self.topic)
    
        def startThread(self):
            self.thread = Thread(target=self.threadMethod)
            self.thread.start()
    
    
    class GUI(wx.Frame):
        def __init__(self, parent, id, title):
            screenWidth = 500
            screenHeight = 400
            screenSize = (screenWidth,screenHeight)
            wx.Frame.__init__(self, None, id, title, size=screenSize)
            self.locationFont = locationFont = wx.Font(12, wx.MODERN, wx.NORMAL, wx.BOLD)
            mainSizer = wx.BoxSizer(wx.VERTICAL)
            #myPanelA = wx.Panel(self, style=wx.SIMPLE_BORDER)
    
            myPanelA = selfUpdatePanel(self, wx.SIMPLE_BORDER, 3, 'Update-panelA', 'Problem solved')
            myPanelA.SetBackgroundColour('#C0FAE0')
            self.myTextA = wx.StaticText(myPanelA, -1, "I have a problem :( ")
            myPanelA.setTextCtrl(self.myTextA)
    
            #myPanelB = wx.Panel(self, style=wx.SIMPLE_BORDER)
            myPanelB = selfUpdatePanel(self, wx.SIMPLE_BORDER, 5, 'Update-panelB', 'Mine too')
            myPanelB.SetBackgroundColour('#C0FAFF')
            self.myTextB = wx.StaticText(myPanelB, -1, "Me too :( ")
            myPanelB.setTextCtrl(self.myTextB)
            mainSizer.Add(myPanelA, 1, wx.EXPAND, 5)
            mainSizer.Add(myPanelB, 1, wx.EXPAND, 5)
            self.SetSizer(mainSizer)
    
            myPanelB.startThread()
            myPanelA.startThread()
    
    
    if __name__=='__main__':
        app = wx.App()
        frame = GUI(parent=None, id=-1, title="Problem Demo")
        frame.Show()
        app.MainLoop()
    

