threading.Thread() meet error

How to use threading.Thread() correct.
My code as follow, some time meet UI error.

def get_all_file_size(self, start_path):
    total = 0
    K, M, G = 1024, 1024**2, 1024**3
    MM = 100 * M # 100MB
    for path, dirs, files in os.walk(start_path):
        for f in files:
            fp = os.path.join(path, f)
            if os.path.isfile(fp):
                size = os.path.getsize(fp)
                total = total + 1
                if (size > MM):
                    self.text_multi_text.AppendText(fp + "  " +  str(float('%.2f' % (size/M))) + "M\n")

    self.text_multi_text.AppendText("\nTask is down, check files number: " + str(total))

def OnExecute(self, event):
    self.text_multi_text.Clear()
    self.text_multi_text.AppendText("More 100M file list\n")

    input = self.text_input.GetValue()
    # self.get_all_file_size(input)

    t1 = threading.Thread(target=self.get_all_file_size, args=(input,))
    t1.start()

You should not call GUI code from outside your main thread.
See e.g. here: https://wiki.wxpython.org/LongRunningTasks or http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

So you can post events to the main thread which will then update things.

You may also do the update inside an EVT_IDLE handler. Often that’s fast enough.
Then use e.g. standard library collections.deque() to pass data to the main thread.
For controlling the worker thread you may use threading.Event.

thanks very much
thanks very much

Simply use CallAfter. Don’t bother trying anything else.

1 Like

yes, wx.CallAfter work right. Thanks

def get_all_file_size(self, start_path):
    total = 0
    K, M, G = 1024, 1024**2, 1024**3
    MM = 100 * M # 100MB
    for path, dirs, files in os.walk(start_path):
        for f in files:
            fp = os.path.join(path, f)
            if os.path.isfile(fp):
                size = os.path.getsize(fp)
                total = total + 1
                if (size > MM):
                    # self.text_multi_text.AppendText(fp + "  " +  str(float('%.2f' % (size/M))) + "M\n")
                    wx.CallAfter(self.text_multi_text.AppendText, fp + "  " +  str(float('%.2f' % (size/M))) + "M\n")

    # self.text_multi_text.AppendText("\nTask is down, check files number: " + str(total))
    wx.CallAfter(self.text_multi_text.AppendText, "\nTask is down, check files number: " + str(total))

I would also add that using pypubsub makes events management much easier (not only with threads).
A usage example is here.
Please note that wx.lib.pubsub is obsolete. Use pypubsub instead.

In a thread : CallAfter + sendMessage .
Something like this : wx.CallAfter(pub.sendMessage, "all_file_size", total=total)

1 Like

good,the better

I’ll do some more learning assessment

I like the hint of sending events down too, usually at abort, to care for a graceful exit… (may be difference of system folk & application guys :hot_face:)