我有一个处理数千个小文件的小脚本。该操作需要一段时间,因此程序将进度输出到控制台。它在以下代码中模拟:
files = 5000 #Number of files
for i in range(files):
sys.stdout.write("\r{0} of {1}".format(i, files))
我喜欢这种输出进度的方式;控制台中只打印一行。但是现在我想从GUI(tkinter)运行这个脚本,我希望将输出打印到状态栏(标签)。我现在有点亏本如何实现这一点。有没有办法在不编辑脚本的情况下处理GUI中的输出?
答案 0 :(得分: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)
但实际上,无论如何,一旦你重写了一些内容,那么删除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)