您将需要从正在执行抓取的线程向您的主应用程序发送消息,以告诉它更新进度条。这意味着您必须使用 wxPython 线程安全方法之一:
- wx.CallAfter
- wx.CallLater
- wx.PostEvent
我认为最简单的方法之一是将 pubsub 与 CallAfter 结合使用。您可以使用 pubsub 将消息发布到需要在其中包含侦听器的对话框。你可以在这里阅读如何做到这一点:http: //www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
更新:
这是一个示例应用程序,它显示了如何从线程定期更新仪表小部件(适用于 wxPython 2.8):
import time
import wx
from threading import Thread
from wx.lib.pubsub import Publisher
########################################################################
class TestThread(Thread):
"""Test Worker Thread Class."""
#----------------------------------------------------------------------
def __init__(self):
"""Init Worker Thread Class."""
Thread.__init__(self)
self.start() # start the thread
#----------------------------------------------------------------------
def run(self):
"""Run Worker Thread."""
# This is the code executing in the new thread.
for i in range(20):
time.sleep(1)
wx.CallAfter(Publisher().sendMessage, "update", "")
########################################################################
class MyProgressDialog(wx.Dialog):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Dialog.__init__(self, None, title="Progress")
self.count = 0
self.progress = wx.Gauge(self, range=20)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.progress, 0, wx.EXPAND)
self.SetSizer(sizer)
# create a pubsub receiver
Publisher().subscribe(self.updateProgress, "update")
#----------------------------------------------------------------------
def updateProgress(self, msg):
""""""
self.count += 1
if self.count >= 20:
self.Destroy()
self.progress.SetValue(self.count)
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.btn = btn = wx.Button(panel, label="Start Thread")
btn.Bind(wx.EVT_BUTTON, self.onButton)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def onButton(self, event):
"""
Runs the thread
"""
btn = event.GetEventObject()
btn.Disable()
TestThread()
dlg = MyProgressDialog()
dlg.ShowModal()
btn.Enable()
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()
如果您使用的是 wxPython 2.9,那么 pubsub 已更新为使用新的 pubsub API。这是一个适用于 wxPython 2.9 的示例:
import time
import wx
from threading import Thread
from wx.lib.pubsub import pub
########################################################################
class TestThread(Thread):
"""Test Worker Thread Class."""
#----------------------------------------------------------------------
def __init__(self):
"""Init Worker Thread Class."""
Thread.__init__(self)
self.start() # start the thread
#----------------------------------------------------------------------
def run(self):
"""Run Worker Thread."""
# This is the code executing in the new thread.
for i in range(20):
time.sleep(1)
wx.CallAfter(pub.sendMessage, "update", msg="")
########################################################################
class MyProgressDialog(wx.Dialog):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Dialog.__init__(self, None, title="Progress")
self.count = 0
self.progress = wx.Gauge(self, range=20)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.progress, 0, wx.EXPAND)
self.SetSizer(sizer)
# create a pubsub receiver
pub.subscribe(self.updateProgress, "update")
#----------------------------------------------------------------------
def updateProgress(self, msg):
""""""
self.count += 1
if self.count >= 20:
self.Destroy()
self.progress.SetValue(self.count)
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.btn = btn = wx.Button(panel, label="Start Thread")
btn.Bind(wx.EVT_BUTTON, self.onButton)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def onButton(self, event):
"""
Runs the thread
"""
btn = event.GetEventObject()
btn.Disable()
TestThread()
dlg = MyProgressDialog()
dlg.ShowModal()
btn.Enable()
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm().Show()
app.MainLoop()