例如:
class DemoFrame(wx.Frame):
def __init__(self):
Initializing
...
self.TextA = wx.StaticText(MainPanel, id = -1, label = "TextAOrWhatever")
self.TextB = wx.StaticText(MainPanel, id = -1, label = "TextBOrWhatever")
...
def StaticTextUpdating(self, ObjectName, Message):
ObjectName.SetLabel(Message)
def WorkerA(self):
while True:
Work on something
UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextA, "Something for TextA", ))
UpdatingThread.start()
time.sleep(randomSecs)
def WorkerB(self):
while True:
Work on something
UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextB, "Something for TextB", ))
UpdatingThread.start()
time.sleep(randomSecs)
...
def StartWorking(self):
Spawn WorkerA thread
Spawn WorkerB thread
...
正如您所看到的,我总是在新线程中更新StaticText
,并且我在任何特定时间点100%确定只有一个线程更新特定对象,但问题是,现在每个然后运行一段时间后,一些物体就消失了。为什么会这样?这是否意味着GUI更新不是线程安全的?也许在某个时间点只能更新一个对象?
加了:
好的,wx.CallAfter应该是上述代码的一个很好的解决方案。但我还有另一个问题,如果按钮事件和SetLabel
同时发生怎么办?这样的事情不会引起麻烦,虽然我没有看到吗?
答案 0 :(得分:4)
大多数wx方法都不是线程安全的。如果要从另一个线程调用wx方法,请使用wx.CallAfter;取代
ObjectName.SetLabel(Message)
使用:
wx.CallAfter(ObjectName.SetLabel, Message)
编辑:一些背景信息
在wx(以及大多数其他UI平台)中,所有UI更新都在称为主线程(或UI线程)的单个线程中执行。这是为了通过避免线程同步的性能损失来使UI更快地工作。
但缺点是,如果我们编写代码来从不同的线程更新UI,则结果是未定义的。有时它可能会起作用,有时它可能会崩溃,有时可能会发生其他一些事情。所以我们应该总是去UI线程来进行UI更新。因此我们使用CallAfter函数在UI线程中执行UI更新功能。
答案 1 :(得分:2)
要记住的主要事情是你不应该在不使用线程安全方法的情况下更新wxPython中的任何内容,例如wx.CallAfter,wx.CallLater或wx.PostEvent。有关详细信息,请参阅http://wiki.wxpython.org/LongRunningTasks或http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/。