【问题标题】:stop tkinter window from freezing while program is sleeping在程序睡眠时停止 tkinter 窗口冻结
【发布时间】:2012-03-04 06:29:50
【问题描述】:

这是我计划中非常重要的一部分,我需要尽快解决,这样任何事情都会有很大帮助。

我的程序由三个相互导入的模块组成。一个模块由我使用 tkinter 的用户界面组成。用户在画布上输入数据,该数据被发送到要处理的第二个程序,然后被发送到第三个模块,其中包含我打算与用户一起逐步完成的算法。

“第一个”和“第三个”模块可以相互交互,并且在解释算法的某些点中,我会更改画布的外观和界面上的一些文本。然后第三个模块应该暂停(我目前正在使用基本的睡眠方法)并等待(理想情况下它将等待用户按下用户界面上的“下一步”按钮)。正是在这一步中,我的界面决定要冻结。

有什么办法可以阻止这种情况吗?

非常感谢。

编辑:我找到了解决此问题的方法。谢谢大家的建议!

【问题讨论】:

  • 三个进程如何通信?
  • 它们以不同的名称相互导入,例如“将 dijk_ui 导入为 ui”,然后是“ui.func()”。

标签: python tkinter


【解决方案1】:

调用time.sleep() 将停止您的程序执行任何操作,直到它完成睡眠。您需要 Tkinter 继续处理事件,直到它应该运行您的代码的下一部分。

为此,请将代码的下一部分放在一个单独的函数中,并让 Tkinter 在它准备好时调用它。通常,您希望在用户触发它时发生这种情况(例如,通过单击按钮),因此您需要将其绑定到事件(docs)。如果您真的希望它在固定时间后发生,您可以在任何 tkinter 小部件 (docs) 上使用 .after() 方法。

GUI 编程需要一些时间来适应。你不会把代码写成一个接一个发生的一系列事情,你编写的代码是由用户所做的事情触发的。

术语说明:如果您的 Python 文件相互导入,则您拥有三个 模块,但它仍然是一个 程序。谈论“第一个程序”会让人感到困惑。

【讨论】:

  • 嗯……看,这是我遇到的问题,因为我的算法包括 while 循环(我想在其中更改界面)所以我觉得我不能将它分成几个函数.
  • @HeUsesPython:可能你真的不需要 while 循环,如果不知道你在做什么就很难说。您可以使用线程,但正确使用会变得复杂。
  • 这是我的代码的解决部分(添加了 cmets):pastebin.com/2JR9P0Vn
【解决方案2】:

H.E.P - 执行此操作的传统方法确实涉及使用单独的线程并使用某种轮询或事件机制来协调“工作”线程和 GUI 线程之间的工作。

但是,正如 Thomas K. 指出的那样,这可能会变得非常复杂和棘手,尤其是在 Python 使用全局解释器锁 (GIL) 等方面,并且还必须应对 Tkinter 的处理循环。

(使用多线程 GUI 的唯一充分理由是,如果您绝对必须确保 GUI 在可能长时间运行的后台任务期间保持响应,我认为这不是这种情况下的问题。)

我建议改为基于生成器的“协同例程”类型的架构。 如“Python (2.7) 语言参考”第 6.8 节所述,[“yield”语句在定义生成器函数时使用,并且仅在生成器函数的主体中使用。在函数定义中使用 yield 语句足以使该定义创建生成器函数而不是普通函数。]

(这有效地构成了协同程序架构的基础。(编辑))

[当调用生成器函数时,它返回一个称为生成器迭代器的迭代器,或者更常见的是生成器。生成器函数的主体通过重复调用生成器的 next() 方法执行,直到引发异常。

当一个 yield 语句被执行时,生成器的状态被冻结,并且 expression_list 的值被返回给 next() 的调用者。 “冻结”是指保留所有局部状态,包括局部变量的当前绑定、指令指针和内部评估堆栈:保存了足够的信息,以便下次调用 next() 时,函数可以像 yield 语句只是另一个外部调用一样执行。] (有关其他背景和一般信息,请参阅“PEP 0342 - Coroutines via Enhanced Generators”。)

这应该允许您的 GUI 按需调用算法规范生成器的下一部分,而不必在操作员按下“下一步”按钮之前将其置于睡眠状态。 您基本上只是创建了一种“特定领域语言”(DSL),仅包含用于演示此特定算法的步骤列表,并且生成器(迭代器)将在调用时简单地执行每个下一步(在需求)。

更简单,更易于维护。

【讨论】:

  • 很难说我是否理解这些。但我会调查一下。
  • 我认为要点是:将yield 语句放入循环中以使solve() 成为生成器(请参阅introduction to generators)。然后你可以调用next(my_generator)再运行一步。
【解决方案3】:

GUI 程序总是等待某些动作发生。当动作发生时,对应于该动作的事件代码被执行。因此,无需致电sleep()。您需要做的就是设置它,以便从适当的事件执行第三个程序。

【讨论】:

    猜你喜欢
    • 2022-01-05
    • 1970-01-01
    • 2018-10-31
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多