如何安全管理wxPython进度对话框线程? [英] How Can I Safely Manage wxPython Progress Dialog Threading?
问题描述
我可以在没有任何用户输入的情况下运行多个计算,并且无需用户担心程序被冻结,因此我试图显示一个进度栏弹出窗口,以使他们了解正在发生的事情.
I have several calculations to run without any user input and without the user worrying about the program having frozen, so I am trying to show a progress bar popup to keep them aware of what's happening.
环顾四周使我相信我需要使用一个单独的线程来执行此操作,因此我想到了这个示例.
Looking around has lead me to believe that I need to use a separate thread to do this, and I came up with this example.
import threading, wx, time
MAX_INT = 10
TEST_TUPLE = [[11, 22],[33,44]]
class mainFrame(wx.Frame):
def __init__(self, parent, ID, title):
wx.Frame.__init__(self, parent, ID, title)
bt = wx.Button(self, wx.ID_OK)
self.Bind(wx.EVT_BUTTON, self.onBt, bt)
def onBt(self,event):
self.dlg = wx.ProgressDialog("title", "message", maximum=MAX_INT)
workThread = threading.Thread(target=self.doWork, args=(TEST_TUPLE,) )
workThread.start()
self.dlg.ShowModal()
def doWork(self, testArg):
# time consuming stuff that affects main GUI
print testArg
for i in range(1, MAX_INT+1):
self.SetPosition((i*4*MAX_INT, i*2*MAX_INT))
time.sleep(1)
print str(i)+" of "+str(MAX_INT)
wx.CallAfter(self.dlg.Update, i, "%i of %i"%(i, MAX_INT))
self.dlg.Destroy()
app = wx.App(False)
fr = mainFrame(None, -1, "Title")
fr.Show()
app.MainLoop()
它似乎按预期工作,但是我在这里跳过了一些家政服务吗?
It seems to work as intended, but is there some housekeeping that I am skipping here?
我用小框架替换了对话框,因此主窗口不会冻结,禁用了按钮,因此不会产生多个框架,并添加了一种粗略的取消方法.
I replaced the dialog with a miniframe so the main window would not freeze, disabled the button so there wouldn't be several frames spawned, and added a crude cancelling method.
import threading, wx, time
MAX_INT = 10
TEST_TUPLE = [[11, 22],[33,44]]
class GaugeFrame(wx.MiniFrame):
def __init__(self, parent, title, maximum):
wx.MiniFrame.__init__(self, parent, title=title, size=(200, 60) )
self.bar = wx.Gauge(self, range=maximum)
self.buCancel = wx.Button(self, label="Cancel")
self.SetBackgroundColour("LTGRAY")
siMainV = wx.BoxSizer(wx.VERTICAL)
siMainV.Add(self.bar)
siMainV.Add(self.buCancel, flag=wx.CENTER)
self.SetSizer(siMainV)
self.Fit()
self.Bind(wx.EVT_BUTTON, self.onCancel, self.buCancel)
def updateGauge(self, value, message=""):
self.bar.SetValue(value)
if message!="":
self.SetTitle(message)
def onCancel(self, e):
self.SetTitle("Cancelling...")
class MainFrame(wx.Frame):
def __init__(self, parent, ID, title):
wx.Frame.__init__(self, parent, ID, title)
self.bt = wx.Button(self, wx.ID_OK)
self.Bind(wx.EVT_BUTTON, self.onBt, self.bt)
def onBt(self, event):
self.gFr = GaugeFrame(self, title="0 of "+str(MAX_INT), maximum=MAX_INT)
self.gFr.Show()
self.gFr.Center()
self.bt.Disable()
workThread = threading.Thread(target=self.doWork, args=(TEST_TUPLE,) )
workThread.start()
def doWork(self, testArg):
# time consuming stuff that affects main GUI
print testArg
for i in range(1, MAX_INT+1):
time.sleep(1)
if self.gFr.GetTitle()=="Cancelling...":
break
print str(i)+" of "+str(MAX_INT)
wx.CallAfter(self.gFr.updateGauge, i, "%i of %i"%(i, MAX_INT))
wx.CallAfter(self.gFr.Destroy)
wx.CallAfter(self.bt.Enable)
app = wx.App(False)
fr = MainFrame(None, -1, "Title")
fr.Show()
app.MainLoop()
推荐答案
看起来不错,只需观察几个即可.
Looks pretty good, just a couple of observations.
- 您不应在辅助线程上调用任何窗口函数.这包括
SetPosition
和Destroy
.您可以像在Update
中那样使用wx.CallAfter
在主线程上调用它们. - 您可能应该允许用户取消处理.
- You should not call ANY window functions on the worker thread. This includes
SetPosition
andDestroy
. You can usewx.CallAfter
to invoke these on the main thread just like you are forUpdate
. - You probably should allow the user to cancel the processing.
这篇关于如何安全管理wxPython进度对话框线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!