Tkinter 代码在没有主循环、更新或之后运行 [英] Tkinter code runs without mainloop, update, or after

查看:43
本文介绍了Tkinter 代码在没有主循环、更新或之后运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用 tkinter 制作 gui 以从这些文件中选择一些 excel 文件和工作表.

I have been trying to use tkinter to make a gui to select some excel files and sheets from those files.

我在 Python 方面有很多经验,但我可能会说是 tkinter 的新手.

I have a lot of experience in python, but I'd probably say a novice at tkinter.

我为选择文件而编写的代码如下所示(可能是错别字,因为我无法在这些文件所在的机器上访问互联网,所以我在此处输入).

The code I have written to select the files is shown below (typos are likely because I cannot access the internet on the machine these files are on, so I am typing it up here).

我的问题是关于 mainloop()、更新函数和 after().我的代码末尾有 mainloop() ,但是我的程序在完成它所做的事情后不会终止(即终端会保留).所以我删除了 mainloop(),现在它可以完美运行,没有任何 mainloop()update()after() 调用.

My question is about mainloop(), the update functions, and after(). I had mainloop() at the end of my code, but my program wouldn't terminate (i.e. the terminal would remain) after it did what it does. So I removed the mainloop() and now it functions perfectly without any mainloop(), update(), or after() calls.

我真的不明白这一点,但我真的很想.我知道 mainloop() 会阻止代码继续运行,直到根关闭,但我认为没有 mainloop() 不会显示任何内容,并且此代码确实在等待用户在继续之前关闭窗口.

I don't really understand this and would really like to. I get that mainloop() stops the code from progressing until the root closes, but I thought nothing would show up without mainloop(), and this code does wait for the user to close the windows before continuing.

我还想知道我是否没有 mainloop(或类似的东西),无论我是否有 root.destroy(),代码仍然可以正常关闭App 类的结尾(在代码中注释).我也不明白.

I was also wondering if I do not have mainloop (or the like), the code still closes fine whether or not I have root.destroy() at the end of the App class (commented in the code). I don't get that either.

这些信息将帮助我在未来制作更好和正确的代码,并希望能改进这一点.仅供参考,我到处寻找这个问题的答案,但找不到,至少是我能理解的.非常感谢.

This information would help me make better and correct code in the future and hopefully improve this one. FYI, I have searched for the answer to this everywhere and could not find one, at least one I could understand. Thanks a bunch.

这是我能想到的最简单的代码.

This is as minimal as I can think of for this code.

import tkinter as tk
from tkinter import ttk

class App:
    def __init__(self, parent):
        self.root = parent
        self.root.withdraw()

        tl = tk.Toplevel(parent)
        b = ttk.Button(tl, text="Test widget")
        b.grid()
        tl.wait_window()

        # This line does not change how the code functions at all
        #self.root.destroy()

    def run(self):
        # Whether or not this is a function in the class or called globally doesn't matter.
        self.root.mainloop()


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)

    # This is the mainloop() call. If I include it, the program does not close after
    # running the code in App.__init__. Without it, it runs perfectly.
    # app.run()

推荐答案

mainloop 为您的 tk.Tk() 应用程序进入一个事件监听循环.

mainloop enters an event listening loop for your tk.Tk() application.

您应该在每个 tkinter 应用程序中只使用 Tk() 创建一个对象.

You should create only one object with Tk() in every tkinter application.

现在这个循环将全局"监听 GUI 事件并调用您注册的回调(事件处理程序).mainloop 调用之前的代码将运行,但在您调用它之前,屏幕中不会显示或更新任何内容.在此之前,不会有任何事件(用户输入、鼠标移动、键盘等)被排队和响应.但是小部件已创建和配置,只是尚未显示.如果你在没有进入主循环的情况下调用 root.update() 你最终会看到窗口闪烁并消失,因为一切都在运行,你强制窗口刷新,但程序突然结束.

Now this loop will "globally" listen for GUI events and will call your registered callbacks (event handlers). Code before the mainloop call will run but nothing will be shown or updated in the screen until you call it. No event (user input, mouse movement, keyboard and others) will be queued and responded to before that. But the widgets are created and configured, just not shown yet. If you call root.update() without ever entering the mainloop you will eventually see the window flash and disappear because everything is running, and you force window refresh, but then suddenly the program ends.

所以配置你的GUI,最后总是运行root.mainloop()

So configure your GUI and in the end always run root.mainloop()

现在,当您调用 wait_window 时,您正在创建一个本地事件循环(如果主循环正在运行,则将其阻塞).有关 Brian 对 wait_window 的完美解释,请参阅此处

Now when you call wait_window, you are creating a local event loop (and blocking the mainloop if it was running). For a perfect explanation of wait_window by Brian see here

发生在您身上的是,您的应用在本地事件循环中愉快地运行,但没有主循环.那将是一件奇怪的事情.即使你像布赖恩解释的那样制作一个模态窗口,你也想在窗口关闭后返回"到主循环.

What happened to you is that your app is happily running with your local event loop, but without mainloop. That would be a strange thing to do. Even if you are making as Brian explains, a modal window, you want to "return" to the mainloop after the window closes.

至于 after 方法,它只是注册一个回调函数,在您选择的时间之后运行,或者在主循环空闲后,使用 after_idle(没有更多刷新,队列中没有事件......,也尽快考虑).如果你想以同样的方式再次运行该函数,它应该在返回之前用 afterafter_idle 重新注册.

As for the after method it just registers a callback function to run after your choosen time, or after the mainloop becames idle, with after_idle (nothing more to refresh, no events in the queue..., also think as soon as possible). And if you want to re-run that function again in the same way it should re-register with after or after_idle before returning.

所以总是使用你的 mainloop() 结束调用 - 或者我应该说事件循环开始调用 :)

So always use your mainloop() ending call - or should I say event loop starting call :)

另外,不要在你的代码中做一些缓慢的事情,或者可能会阻塞循环的事情,比如调用 sleep 或任何其他阻塞函数.这将冻结 GUI,直到块结束.

Also, don't do things in your code that are slow, or that may block the loops, such as calling sleep or any other blocking function. That will freeze the GUI, until the block ends.

这篇关于Tkinter 代码在没有主循环、更新或之后运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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