简体   繁体   English

在tkinter中使用sys.stdout.write(“\\ r \\ n ...”)

[英]Using sys.stdout.write(“\r…”) in tkinter

I have a small script that processes many thousand small files. 我有一个处理数千个小文件的小脚本。 The operation takes a while, so the program outputs progress to the console. 该操作需要一段时间,因此程序将进度输出到控制台。 It's simulated in the code below: 它在以下代码中模拟:

files = 5000 #Number of files
    for i in range(files):
        sys.stdout.write("\r{0} of {1}".format(i, files))

I like this way of outputting progress; 我喜欢这种输出进度的方式; only a single line is printed in the console. 控制台中只打印一行。 However now I want to run this script from a GUI (tkinter), and I want the output to be printed to a statusbar (a label). 但是现在我想从GUI(tkinter)运行这个脚本,我希望将输出打印到状态栏(标签)。 I'm a bit at loss right now how to implement this. 我现在有点亏本如何实现这一点。 Is there a way I can handle the output in the GUI without editing the script? 有没有办法在不编辑脚本的情况下处理GUI中的输出?

While you can intercept stdout and do whatever you want with it, this is a bad idea—and, even if you do that, your program doesn't make sense in the first place. 虽然你可以截取stdout并随心所欲地做任何事情,但这是一个坏主意 - 即使你这样做,你的程序首先也没有意义。

You can't run an operation that "takes a while" in a GUI app. 您无法在GUI应用程序中运行“需要一段时间”的操作。 While the operation is running, your GUI's main loop is not running, which means the entire GUI is frozen. 当操作正在运行时,GUI的主循环未运行,这意味着整个GUI被冻结。 Besides giving you a beachball, this also means that any changes you make won't be visible until you return. 除了给你一个沙滩球,这也意味着你做出的任何改变在你回来之前是不可见的。

What if you did the operation in another thread? 如果你在另一个线程中执行操作怎么办? Well, then it wouldn't prevent the GUI from running… but you can't talk to Tkinter widgets from any thread but the main thread, so that doesn't help. 那么,它不会阻止GUI运行...但你不能从任何线程但主线程与Tkinter小部件交谈,所以这没有帮助。

So, what you need to do is do a single step of your operation at a time, each time scheduling the rest of the operation as a callback to do later. 因此,您需要做的是一次执行一个操作步骤,每次将其余操作安排为稍后执行的回调。

For example: 例如:

class StatusWriter(object):
    def write(self, msg):
        statusbar.config(text=msg[1:])

def count():
    sys.stdout = StatusWriter()
    i = 0
    def step():
        nonlocal i
        sys.stdout.write("\r{} of {}".format(i, 50))
        i += 1
        if i == 50:
            sys.stdout = sys.__stdout__
        else:
            root.after(100, step)
    root.after(100, step)

But really, once you're rewriting things anyway, it makes a lot more sense to also remove the stdout-replacing hackery: 但实际上,一旦你重写了一些东西,那么删除stdout替换hackery也更有意义:

def count():
    sys.stdout = StatusWriter()
    i = 0
    def step():
        nonlocal i
        statusbar.config(text="{} of {}".format(i, 50))
        i += 1
        if i == 50:
            sys.stdout = sys.__stdout__
        else:
            root.after(100, step)
    root.after(100, step)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM