当前位置: 首页 > 知识库问答 >
问题:

为什么ttk Progressbar在Tkinter中的进程后出现

苏季同
2023-03-14

我想在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) 

共有2个答案

祁奇略
2023-03-14

这里有另一个相当简单的解决方案,不需要混合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()
薛烨霖
2023-03-14

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

为了防止这种情况,你可以使用一个辅助线程来运行你的函数,并在主线程中运行图形用户界面及其进度条。为了让您了解如何做到这一点,这里有一个简单的例子,我从另一个(不相关的)进度条问题中的代码中导出,以展示这样的事情是多么容易完成。注意:通常建议不要让次要线程直接访问主线程的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()
 类似资料:
  • 我已经编写了一个程序,它监视一个目录,并在用户添加文件时发出警报,该文件的特定格式为用户名。文件它工作正常,但当我在收到新文件被添加的警报时按ok,程序退出,我希望它保持运行。 下面我写的代码将作为该应用程序中另一个PYQT应用程序的子进程运行。因此,我不会执行main(),而只是实例化SendMyFiles对象。

  • 昨天我在python中使用多重处理处理了大约2000万行的日志文件。 启动名为“producer”的进程,逐行读取文件并将其放入队列 代码在下面 结果很奇怪,工作完成后,消费者进程不会终止,并且主函数在连接()处被阻塞。 使用以下不同的套装和代码进行测试: 使用test_get_ip()而不进行多处理来处理大小日志文件,效果很好 那么,有什么问题?列表中有限制吗?有什么我错过的吗? 我的机器环境是

  • 然后权限委托类处理权限逻辑: 这段代码工作得非常好,直到我强制流程死亡(我在开发人员工具中选择了Don't keep activities复选框)。之后,我从后台返回,权限对话框仍然存在(因为onCreate再次被触发,权限检查再次被执行)。 问题是,在我按下permission对话框中的任何按钮后,onRequestPermissionsResult方法不会在片段中被触发。我查看了logcat,

  • 问题内容: 维基百科说:“一个终止但从未被其父级等待的子进程变成了僵尸进程。” 我运行此程序: 这会创建一个僵尸进程,但我不明白为什么在这里创建了僵尸进程? 该程序的输出是 但是在这种情况下,为什么“子进程终止但没有被其父进程等待”呢? 问题答案: 在您的代码中,创建了僵尸(带有以下箭头的注释): 为什么?因为你从来没有上过。调用时,它将返回有关进程的事后信息,例如其退出代码。不幸的是,当进程退出

  • 我正在eclipse上处理一个程序,遇到一个错误,上面写着:线程“main”java.lang.error:Unresolved compilation problem:at main.main(main.java:19)我是编程新手,如果您告诉我这个错误是什么,以及我如何修复它,这将非常重要。谢谢你!

  • 问题内容: 在下面的示例中(来自我的Coursepack),我们希望给该Square实例c1一些其他对象的引用p1,但前提是这两个对象是兼容类型的。 我在这里不明白的是,我们首先检查p1确实为Square,然后仍将其强制转换。如果是Square,为什么要投射? 我怀疑答案在于表观类型和实际类型之间的区别,但是我还是很困惑…… 编辑: 编译器将如何处理: Edit2: 是instanceof检查实际