The Python Oracle

wxPython Pango error when using a while True loop in a thread

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Techno Intrigue Looping

--

Chapters
00:00 Wxpython Pango Error When Using A While True Loop In A Thread
00:58 Accepted Answer Score 8
02:07 Answer 2 Score 1
02:44 Thank you

--

Full question
https://stackoverflow.com/questions/1432...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #multithreading #wxpython

#avk47



ACCEPTED ANSWER

Score 8


I am not exactly sure if that is what causes you problem, but... You should not interact with the GUI from another thread. You should use wx.CallAfter(). I would consider adding sleep inside the loop also.

wx.CallAfter() documentation says:

Call the specified function after the current and pending event handlers have been completed. This is also good for making GUI method calls from non-GUI threads. Any extra positional or keyword args are passed on to the callable when it is called.

Updated code would than be:

import wx
import thread
import time

class Example(wx.Frame):
    def __init__(self, parent): 
        wx.Frame.__init__(self,parent)
        self.InitUI()

    def InitUI(self):
        self.SetSize((250, 200))
        self.Show(True)

        self.text = wx.StaticText(self, label='',pos=(20,30))

        thread.start_new_thread(self.watch,(self,None))

    def watch(self,dummy,e):
        while True:
            time.sleep(0.1)
            wx.CallAfter(self.text.SetLabel, 'Closed')

def main():
    ex = wx.App()
    Example(None)
    ex.MainLoop()    

if __name__ == '__main__':
    main() 

Maybe you can also consider using wx.Timer.

BTW: Your code runs OK on my PC with Windows 7 and wxPython 2.8.




ANSWER 2

Score 1


In addition to the no updates from background threads rule, I've found that in similar situations (high frequency update of UI objects) that it really helps to only update the value if it has changed from what is already displayed. That can greatly reduce the load on the application because if the value does not change then there will be no need for sending and processing paint events, moving pixels to the screen, etc. So in this example I would add a new method that is called via CallAfter that compares the current value in the widget with the requested value, and only calls SetLabel if they are different.