我有一個GUI應用程序,它使用子進程啓動一些命令,然後通過從subprocess.Popen.stdout中讀取並使用wx.ProgressDialog來顯示此命令的進度。我已經在Linux下編寫了該應用程序,它在那裏完美地工作,但我現在正在Windows下進行一些測試,似乎試圖更新進度對話框會導致應用程序掛起。沒有錯誤信息或任何內容,所以我很難弄清楚發生了什麼。下面是一個簡單的代碼:wxPython +子流程。 ProgressDialog無法在windows下工作
子進程在單獨的線程用這種方法在主線程啓動:
def onOk(self,event):
""" Starts processing """
self.infotxt.Clear()
args = self.getArgs()
self.stringholder = args['outfile']
if (args):
cmd = self.buildCmd(args, True)
if (cmd):
# Make sure the output directory is writable.
if not self.isWritable(args['outfile']):
print "Cannot write to %s. Make sure you have write permission or select a different output directory." %os.path.dirname(args['outfile'])
else:
try:
self.thread = threading.Thread(target=self.runCmd,args=(cmd,))
self.thread.setDaemon(True)
self.thread.start()
except Exception:
sys.stderr.write('Error starting thread')
而這裏的RUNCMD方法:
def runCmd(self, cmd):
""" Runs a command line provided as a list of arguments """
temp = []
aborted = False
dlg = None
for i in cmd:
temp.extend(i.split(' '))
# Use wx.MutexGuiEnter()/MutexGuiLeave() for anything that accesses GUI from another thread
wx.MutexGuiEnter()
max = 100
stl = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME
dlg = wx.ProgressDialog("Please wait", "Processing...", maximum = max, parent = self.frame, style=stl)
wx.MutexGuiLeave()
# This is for windows to not display the black command line window when executing the command
if os.name == 'nt':
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
else:
si = None
try:
proc = subprocess.Popen(temp, shell=False, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except Exception:
sys.stderr.write('Error executing a command. ')
# Progress dialog
count = 0
while True:
line=proc.stdout.readline()
count += 1
wx.MutexGuiEnter()
if dlg.Update(count) == (True, False):
print line.rstrip()
wx.MutexGuiLeave()
if not line: break
else:
print "Processing cancelled."
aborted = True
wx.MutexGuiLeave()
proc.kill()
break
wx.MutexGuiEnter()
dlg.Destroy()
wx.GetApp().GetTopWindow().Raise()
wx.MutexGuiLeave()
if aborted:
if os.path.exists(self.stringholder):
os.remove(self.stringholder)
dlg.Destroy()
proc.wait()
同樣,這在Linux下正常工作,但在Windows上凍結。如果我刪除dlg.Update()行,它也可以正常工作。子進程輸出在主窗口中打印出來並顯示ProgressDialog,只是進度條不移動。我錯過了什麼?
如果您可以將問題縮小到我們可以在我們的計算機上實際嘗試的非常小的可運行應用程序,那將是非常好的。 – Fenikso
如果我找不到解決方案,我會盡力做到,但是您可能需要一些簡單的C應用來測試它。我在子進程中執行的命令已被修改以避免任何緩衝,所以proc.stdout.readline()在生成後立即得到輸出。否則,由於C stdout實現(在寫入管道時使用完全緩衝),命令完成之前輸出不可用。這可以在linux上使用'unbuffer'來解決,但是在windows上需要對C代碼進行一些修改。如果我無法使用wx.CallAfter解決問題,我會稍後再回來。 – jaho