【问题标题】:Tkinter Toplevel - strange behavior as built windows exeTkinter Toplevel - 构建Windows exe的奇怪行为
【发布时间】:2014-03-20 21:18:30
【问题描述】:

我将 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) 子句完成。然后这些函数都被调用。他们所做的事情会导致出现第二个顶级窗口,该窗口本质上是主窗口的克隆。 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 窗口的情况下启动进程?

【问题讨论】:

    标签: python windows tkinter


    【解决方案1】:

    好的,像往常一样,解决方案是我应该有 RTFM。根据docs 的说法,当在 Windows 上冻结时,必须调用一个魔术函数来修复 multiprocessing 的奇怪问题。

    if __name__ == "__main__":
        freeze_support()
        root = tk.Tk()
        root.withdraw()
        app = impy()
        root.mainloop()
    

    【讨论】:

    • 为什么不只是 app.mainloop()?为什么要创建root然后撤回呢?
    • 此示例的应用程序类基于 Toplevel 而不是 Frame。所以它不需要默认的顶层。一切都内置在二级顶级小部件中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    • 2017-06-13
    • 1970-01-01
    • 2020-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多