wxPython +子进程。 ProgressDialog 在 Windows 下不起作用
我有一个 GUI 应用程序,它使用 subprocess 启动一些命令,然后通过读取 subprocess.Popen.stdout 并使用 wx.ProgressDialog 显示该命令的进度。我已经在 Linux 下编写了该应用程序,并且运行完美,但我现在正在 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,只是进度条不移动。我缺少什么?
I have a GUI application which launches some commands using subprocess and then shows the progress of this commands by reading from subprocess.Popen.stdout and using wx.ProgressDialog. I've written the app under Linux and it works flawlessly there, but I'm now doing some testing under windows and it seems that trying to update the progress dialog causes the app to hang. There are no error messages or anything, so it's difficult for me to figure out what's happening. Below is a simplified code:
The subprocess is launched in separate thread by this method in main thread:
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')
And here's the runCmd method:
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()
Again this works fine under Linux, but freezes on Windows. If I remove dlg.Update() line it also works fine. The subprocess output is printed out in main window and ProgressDialog is shown, just progressbar doesn't move. What am I missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尽量不要使用
wx.MutexGuiEnter
和wx.MutexGuiLeave
。您可以使用 wx.CallAfter 从另一个线程更新 GUI。我以前从未见过有人在 wx 应用程序中使用这些互斥体,甚至在使用线程的教程或示例中也没有见过。Try not using
wx.MutexGuiEnter
andwx.MutexGuiLeave
. You can handle updating the GUI from another thread usingwx.CallAfter
. I have never seen anyone using those mutexes in wx application before and not even in tutorials or examples of using threads.