我正在使用tk作为项目的GUI。我有一些非常奇怪的行为,但只作为Windows上构建的可执行文件。本质上我有一个函数启动一个新的进程,并需要在完成后更新一些GUI元素。这适用于OS X和运行解释的Windows。它作为OS X二进制文件工作正常。但作为Windows二进制文件,代码导致第二个主窗口出现原因不明。
该应用程序通过以下方式启动:
root = tk.Tk()
root.withdraw()
app = impy()
root.mainloop()
,其中
class impy(tk.Toplevel):
然后用户点击某个按钮会导致其运行:
dialog = Progress_Dialog()
dialog.set_text('Implosion generation...')
dialog.update_idletasks()
# Use helper function:
parent_conn, child_conn = Pipe()
p = Process(target=ImplosionRunner.run, args=(child_conn,))
self.processes.append(p)
# start the process and send implosion:
p.start()
try:
parent_conn.send(self.imp)
except:
raise Exception('Implosion object passed to ImplosionRunner is not pickleable!')
obj = None
# Loop while the process is active:
def callback():
nonlocal dialog, p, parent_conn
if dialog.cancelled:
dialog.withdraw()
p.terminate()
return
# Try to receive from the Pipe:
if parent_conn.poll():
# Update the progress, or end otherwise:
obj = parent_conn.recv()
if isinstance(obj, Exception):
from tkinter.messagebox import showerror
showerror('Error!', 'A problem occurred generating the implosion (class '+self.imp.name()+')\n'+obj.__str__())
dialog.withdraw()
p.terminate()
return
elif isinstance(obj, float):
dialog.set(100*obj)
elif isinstance(obj, Implosion):
# Pass info back to the main app:
self.imp = obj
self.after(10, self.__postImplosion__)
dialog.withdraw()
p.terminate()
return
self.after(25, callback)
self.after(10, callback)
回调循环最终通过elif isinstance(obj, Implosion)
子句完成。然后调用这些函数。他们所做的事情导致出现第二个Toplevel窗口,它实际上是主窗口的克隆。 UI操作应用于克隆。 __postImplosion__
方法只是:
for key in self.modControlChecks.keys():
self.modControlChecks[key].configure(state=tk.NORMAL)
# Run any modules that were already checked in refresh mode
for key in self.modControlChecks.keys():
self.modRedisplay[key] = (self.modControlVars[key].get() == 1)
for mod in allModules():
if self.modRedisplay[mod.name()]:
self.__runModule__(mod.name())
它只需循环一些复选框并启用它们。我非常困惑,因为这只是Windows二进制文件的一个问题。有什么想法吗?
更新:更多问题排查:调用p.start()
后会立即显示额外的主窗口。所以这似乎是一些奇怪的行为。为什么我不能在没有额外的Tk窗口的情况下启动进程?
答案 0 :(得分:1)
好的,像往常一样,解决方案是我应该有RTFM。根据{{3}},在Windows上冻结时,必须调用一个魔术函数来修复multiprocessing
的奇怪问题。
if __name__ == "__main__":
freeze_support()
root = tk.Tk()
root.withdraw()
app = impy()
root.mainloop()