【问题标题】:Why ttk Progressbar appears after process in Tkinter为什么 ttk Progressbar 在 Tkinter 处理后出现
【发布时间】:2013-04-30 07:32:06
【问题描述】:

我想在Tkinter 菜单命令上创建一个大文本,并通过进度条提供视觉支持。虽然进度条是在随后的耗时循环之前启动的,但只有在创建并显示大文本后才会显示进度条。

def menu_bar(self):
    self.create_menu.add_command(label="Create large file", 
    command=self.create_large_file)

def create_large_file(self):
    self.progressbar = ttk.Progressbar(self.master, mode='indeterminate')
    self.progressbar.pack()
    self.progressbar.start()
    self.text.delete(1.0, 'end')
    self.file_content = []

i = 0
while i < 2000000:
    line = lfd.input_string
    self.file_content.append(line + "\n")
    i += 1

self.file_content = ''.join(self.file_content)
self.text.insert(1.0, self.file_content) 

【问题讨论】:

  • mode='indeterminate' 进度条的默认更新间隔为 50 毫秒,因此您的循环可能并不那么耗时。尝试在调用其start() 方法时指定较小的时间值参数。
  • 这似乎没有帮助。我指定了一个较小的时间值作为更新间隔,并增加了进程。我等大约。循环处理 3 秒后,才会出现进程栏。

标签: python progress-bar ttk


【解决方案1】:

我认为问题在于耗时的循环正在阻止 tkinter 事件循环 mainloop() 运行。换句话说,当您的工作密集型函数与 GUI 在同一线程中运行时,它会通过占用解释器来干扰它。

为了防止这种情况,您可以使用辅助Thread 来运行您的函数并在主线程中运行 GUI 及其进度条。为了让您了解如何做到这一点,这里有一个简单的例子,我从另一个(不相关的)progressbar question 中的代码派生出来,以展示这样的事情是多么容易做到。 注意: 一般建议不要让辅助线程直接访问主线程的tkinter 对象。

from Tkinter import *
import ttk

import time
import threading

def foo():
    time.sleep(5) # simulate some work

def start_foo_thread(event):
    global foo_thread
    foo_thread = threading.Thread(target=foo)
    foo_thread.daemon = True
    progressbar.start()
    foo_thread.start()
    root.after(20, check_foo_thread)

def check_foo_thread():
    if foo_thread.is_alive():
        root.after(20, check_foo_thread)
    else:
        progressbar.stop()

root = Tk()
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
progressbar = ttk.Progressbar(mainframe, mode='indeterminate')
progressbar.grid(column=1, row=100, sticky=W)

ttk.Button(mainframe, text="Check",
           command=lambda:start_foo_thread(None)).grid(column=1, row=200,
                                                       sticky=E)

for child in mainframe.winfo_children():
    child.grid_configure(padx=5, pady=5)
root.bind('<Return>', start_foo_thread)

root.mainloop()

【讨论】:

  • martineau,根据您的良好回答,我发布了另一个问题,因为我在将您的解决方案实施到我的程序中时遇到了困难。也许您对此也有想法:stackoverflow.com/questions/16420041/…
  • @solarisman:我会看看另一个问题。我想知道为什么你在接受我的答案后没有在这里投票。
  • 抱歉,我还是新手。我忘记了,现在我做到了。
【解决方案2】:

这是另一个相当简单的解决方案,不需要混合 Tkinter 和多线程。要使用它需要能够在耗时功能期间多次调用进度条小部件的update_idletasks() 方法。

from Tkinter import *
import ttk

import time

def foo(progressbar):
    progressbar.start()
    for _ in range(50):
        time.sleep(.1) # simulate some work
        progressbar.step(10)
        progressbar.update_idletasks()
    progressbar.stop()

root = Tk()

mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
progressbar = ttk.Progressbar(mainframe, mode='indeterminate')
progressbar.grid(column=1, row=100, sticky=W)

ttk.Button(mainframe, text="Check",
           command=lambda:foo(progressbar)).grid(column=1, row=200, sticky=E)

for child in mainframe.winfo_children():
    child.grid_configure(padx=5, pady=5)
root.bind('<Return>', lambda event:foo(progressbar))

root.mainloop()

【讨论】:

  • 刚刚遇到这个......我是否正确的是......step(10)有点像进度条的速度参数 - 这是正常不确定的有趣“增强”模式。
  • @RFlack:是的,它有效地控制了弹跳矩形在'indeterminate' 模式Progressbar 中来回移动的速度。
  • 我在让这一切正常工作时遇到了很多问题。我试图将我的 ProgressBar 类放在一个单独的模块中。我发现我必须使用我收集的 update() 是危险的; update_idletasks() 导致进度条窗口空白。我会做更多的挖掘,但你是这方面的专家吗?我已经发布了一个没有太多评论的问题
  • @RFlack:抱歉,不,我不是tkinter 专家。我确实快速浏览了您的另一个问题,我注意到的一件事是ttk.ProgressBar 实例的bar.Progressbar.start()bar.Progressbar.set()bar.Progressbar.stop() 方法在您自己的ProgressBar 类的实现中永远不会被调用。如果您希望自己的工作正常,所有这些都需要按照我的答案中的代码所示进行调用。这样做之后,update_idletasks() 就是您需要使用的全部。
  • @RFlack:顺便说一句,你不应该将你的类方法名的第一个字母大写——参见PEP 8 - Style Guide for Python Code。如果您不遵守约定,它会使您的代码混乱且更难理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-01
  • 2020-09-20
  • 1970-01-01
  • 2022-06-19
相关资源
最近更新 更多