1

我有一个处理数千个小文件的小脚本。该操作需要一段时间,因此程序将进度输出到控制台。它在下面的代码中进行了模拟:

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

我喜欢这种输出进度的方式;控制台中只打印一行。但是现在我想从 GUI(tkinter)运行这个脚本,并且我希望将输出打印到状态栏(标签)。我现在有点不知所措如何实现这一点。有没有一种方法可以在不编辑脚本的情况下处理 GUI 中的输出?

4

1 回答 1

3

虽然您可以拦截stdout并使用它做任何您想做的事情,但这是个坏主意——而且,即使您这样做,您的程序一开始就没有任何意义。

您不能在 GUI 应用程序中运行“需要一段时间”的操作。当操作运行时,您的 GUI 的主循环没有运行,这意味着整个 GUI 被冻结。除了给您一个沙滩球外,这还意味着您所做的任何更改都将在您返回之前不可见。

如果您在另一个线程中进行操作怎么办?好吧,那么它不会阻止 GUI 运行……但是除了主线程之外,您不能从任何线程与 Tkinter 小部件对话,所以这无济于事。

因此,您需要做的是一次执行一个操作步骤,每次将其余操作安排为稍后执行的回调。

例如:

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)

但实际上,无论如何,一旦你重写了东西,删除替换标准输出的黑客就更有意义了:

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)
于 2013-10-22T19:41:13.543 回答