【问题标题】:Tkinter problems with GUI when entering while loop进入while循环时GUI出现Tkinter问题
【发布时间】:2013-03-24 19:01:12
【问题描述】:

我有一个简单的 GUI,它从另一个 python 文件运行各种脚本,一切正常,直到 GUI 运行一个包含 while 循环的函数,此时 GUI 似乎崩溃并变得不活动。是否有人对如何克服这个问题有任何想法,因为我相信这与正在更新的 GUI 有关,谢谢。下面是我的 GUI 的简化版本。

图形界面

#!/usr/bin/env python
# Python 3

from tkinter import *
from tkinter import ttk
from Entry import ConstrainedEntry
import tkinter.messagebox
import functions

AlarmCode = "2222"

root = Tk()
root.title("Simple Interface")
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)


ttk.Button(mainframe, width=12,text="ButtonTest", 
           command=lambda: functions.test()).grid(
             column=5, row=5, sticky=SE)

for child in mainframe.winfo_children():
    child.grid_configure(padx=5, pady=5)

root.mainloop()

功能

def test():
    period = 0
    while True:
        if (period) <=100:
            time.sleep(1)
            period +=1
            print(period)
        else:
            print("100 seconds has passed")
            break

上面会发生的是,当循环运行时,应用程序会崩溃。如果在这段时间过去后我在 else 语句中插入一个中断,一切都会正常工作。我希望用户能够在循环中单击,因为此 GUI 将运行许多不同的功能。

【问题讨论】:

  • time.sleep(1) 正是您满足“请冻结我的 GUI 一秒钟”要求的方式。

标签: user-interface python-3.x tkinter


【解决方案1】:

不要在与 Tkinter 代码相同的线程中使用 time.sleep:它会冻结 GUI,直到 test 的执行完成。为避免这种情况,您应该使用after 小部件方法:

# GUI
ttk.Button(mainframe, width=12,text="ButtonTest", 
           command=lambda: functions.test(root))
           .grid(column=5, row=5, sticky=SE)

# functions
def test(root, period=0):
    if period <= 100:
        period += 1
        print(period)
        root.after(1000, lambda: test(root, period))
    else:
        print("100 seconds has passed")

更新:

在您的评论中,您还补充说您的代码不会使用time.sleep,因此您的原始示例可能不是最合适的。在这种情况下,您可以创建一个新线程来运行您的密集代码。

请注意,我首先发布了 after 的替代方案,因为只有在完全必要时才应使用多线程 - 它会增加应用程序的开销,并增加调试代码的难度。

from threading import Thread

ttk.Button(mainframe, width=12,text="ButtonTest", 
           command=lambda: Thread(target=functions.test).start())
           .grid(column=5, row=5, sticky=SE)

# functions
def test():
    for x in range(100):
        time.sleep(1) # Simulate intense task (not real code!)
        print(x)
    print("100 seconds has passed")

【讨论】:

  • 是否有任何关于root.after的详细在线解释,因为我的代码在实践中不会使用时间,这只是一个示例,因为我的实际代码将监视通过和外部连接设备的输入。
  • 我想说的是,如果我在 while 循环中有一个简单的打印语句,这会导致同样的问题。
  • @user1978826 我已经更新了答案。我建议您编辑您的问题以反映您在 cmets 中提到的声明。
  • 是的,但是在上面的示例中,当我尝试使用根解决方案时,我只是得到一个全局根未定义错误
  • @user1978826 那是因为您的函数位于不同的文件中,因此您必须将 root 作为参数传递 - 作为旁注,请考虑在同一个文件中包含此类回调,并且仅将非 GUI 相关的功能移动到单独的模块中。
猜你喜欢
  • 2023-01-31
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-17
  • 2011-06-19
  • 1970-01-01
相关资源
最近更新 更多