虽然循环在 tkinter 窗口中无法正常工作 [英] While loop not working properly in tkinter window

查看:46
本文介绍了虽然循环在 tkinter 窗口中无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前遇到一个问题,我试图在 tkinter 窗口内运行 while 循环.它一直等到 while 循环完成才能实际显示窗口.我想要发生的是让窗口出现,然后 while 循环将开始.经过研究,我发现它与 root.mainloop() 函数有关,但我不确定如何更改它.

I am currently having an issue where I am trying to run a while loop inside a tkinter window. It waits until the while loop finishes for it to actual show the window. What I want to happen is for the window to come up, and then the while loop will begin. After research I found that it is something to do with the root.mainloop() function, but I am not sure how to change it.

#creates new window
root = Tk()

#makes backdrop picture of map
C = Canvas(root, bg="black", height=780, width=1347)
C.grid(row=0,column=0)
filename = PhotoImage(file = "map4.png")
background_label = Label(root, image=filename)
background_label.place(x=0, y=0, relwidth=1, relheight=1)

totalDeaths = 0
totalCases = 0
totalPopulation = 15000
dayCount = 0

#loops until total deaths = population
while totalDeaths < totalPopulation:
    totalDeaths += 1
    time.sleep(1)

root.mainloop()

推荐答案

while 循环完全按照设计工作.您实际上已经要求它休眠 15,000 秒,这就是它正在做的事情.当它处于睡眠状态时,tkinter 无法刷新显示或处理任何类型的事件.

The while loop is working exactly as designed. You have in effect asked it to sleep for 15,000 seconds so that's what it is doing. While it is sleeping, tkinter is unable to refresh the display or process events of any type.

在创建 GUI 时,一条经验法则是您永远不应该在与 GUI 相同的线程中使用大的 while 循环.GUI 已经有一个一直在运行的无限循环.

When creating GUIs, a rule of thumb is that you should never have a large while loop in the same thread as the GUI. The GUI already has an infinite loop running all the time.

因此,第一步是将循环内的代码移动到函数中.在 UI 中,将 UI 代码与非 UI 代码分开通常很好,因此在这种情况下,我推荐两个函数:一个用于计算,另一个用于更新显示.这样可以更轻松地替换 UI 或计算方法,而无需重写整个程序.使用单元测试也可以更轻松地测试计算功能.

So, the first step is to move the code which is inside your loop to a function. In a UI it's often good to separate the UI code from non-UI code, so in this case I recommend two functions: one to do the calculation and one to update the display. This will make it easier to replace either the UI or the method of calculation without having to rewrite the whole program. It will also make it easier to test the calculation function with a unit test.

那么,让我们从计算死亡人数的函数开始.根据对其他答案的评论,您似乎有一个复杂的公式来执行此操作,但只需增加总数即可进行模拟.

So, let's start with a function that calculates the deaths. Based on comments to other answers, it appears that you have a complicated formula for doing that but simply incrementing the total is good enough for a simulation.

def update_deaths():
    global totalDeaths
    totalDeaths += 1

接下来,您需要一种显示这些死亡人数的方法.您发布的代码没有任何方法可以做到这一点,因此此解决方案需要添加一个 Label 来显示当前的死亡人数.如何真正做到这一点取决于您,但以下代码说明了一般原则:

Next, you need a way to display those deaths. The code you posted doesn't have any way to do that, so this solution requires the addition of a Label to show current deaths. How you do it for real is up to you, but the following code illustrates the general principle:

death_label = Label(...)
...
def update_display():
    global totalDeaths
    death_label.configure(text=f"Total Deaths: {totalDeaths}")

难题的第三部分是模拟 while 循环的代码.它的工作是更新死亡人数,然后每秒更新一次显示,直到整个人口死亡.

The third piece of the puzzle is the code to simulate your while loop. Its job is to update the deaths and then update the display every second until the entire population has died.

我们使用 after 方法来做到这一点,该方法可以安排一个函数在未来运行.通过使用 after 而不是 sleep,它允许 mainloop 能够继续处理诸如按钮点击、按键按下、更新显示的请求等事件.>

We do that with the after method which can schedule a function to be run in the future. By using after rather than sleep, it allows mainloop to be able to continue to process events such as button clicks, key presses, requests to update the display, etc.

def simulate_deaths():
    global totalDeaths
    global totalPopulation
    
    update_deaths()
    update_display()

    if totalDeaths < totalPopulation:
        root.after(1000, simulate_deaths)

如果在程序开始时调用此函数一次,它将继续每秒调用一次,直到满足条件.

If you call this function once at the start of your program, it will continue to be called once a second until the condition is met.

after 方法返回一个标识符,您可以使用它在下一次迭代之前取消函数.如果您将其保存在全局变量(或实例变量,如果您正在使用类)中,您可以通过使用该标识符调用 after_cancel 来停止模拟.

The after method returns an identifier, which you can use to cancel the function before its next iteration. If you save that in a global variable (or instance variable if you're using classes), you can stop the simulation by calling after_cancel with that identifier.

例如:

def simulate_deaths():
    global after_id
    ...
    after_id = root.after(1000, simulate_deahts)
    

def stop_simulation():
    root.after_cancel(after_id)

这篇关于虽然循环在 tkinter 窗口中无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆