【问题标题】:Tkinter progressbar hangs program and doesn't continueTkinter 进度条挂起程序并且不继续
【发布时间】:2019-03-28 17:57:15
【问题描述】:

我尝试使用线程来实现 Tkinter 进度条,只是为了查看程序何时运行,并在程序结束时关闭进度条。

import tkinter
import ttk
import time
import threading

def task(root):
    ft = ttk.Frame()
    ft.pack(expand=True, fill=tkinter.BOTH, side=tkinter.TOP)
    pb_hD = ttk.Progressbar(ft, orient='horizontal', mode='indeterminate')
    pb_hD.pack(expand=True, fill=tkinter.BOTH, side=tkinter.TOP)
    pb_hD.start(50)
    root.mainloop()


def process_of_unknown_duration(root):
    time.sleep(5)
    root.destroy()


def pBar():
    root = tkinter.Tk()
    t1=threading.Thread(target=process_of_unknown_duration, args=(root,))
    t1.start()
    task(root)  # This will block while the mainloop runs
    t1.join()


if __name__ == '__main__':
    pBar()
    #some function

我的问题是,一旦进度条启动,程序就会挂起,不会做任何其他事情。有什么提示吗?

【问题讨论】:

  • tkinter 不支持多线程。您可以使用线程,但它们不能与 GUI 交互。一种解决方法是定期让mainloop() 通过通用after() 小部件函数调用函数。被调用函数可以访问tkinter函数和小部件。
  • 我运行了你的代码,它可以工作。我必须改变的一件事是'import ttk'行。我只是把它改成了'from tkinter import ttk'
  • @RockAndRoleCoder 嗯,我试过了,但似乎没有用
  • 也许尝试将你的 root.destroy 移到你的线程之外,并告诉它等待 6 秒而不是 5 秒(让线程有一些时间)。我很好奇要求线程销毁主线程是否会导致您的问题。

标签: python tkinter progress


【解决方案1】:

这是因为您致电root.mainloop() is blocking the execution of your code。它基本上代表了您的 UI 的循环。您可能想查看this answer 以获取由按钮启动的进度条。

【讨论】:

  • 我使用您链接的解决方案进行了尝试,当程序运行并完成时,状态栏本身不会移动并最终冻结。
【解决方案2】:

你还对这个问题感兴趣吗?尝试对根对象使用update() 方法,而不是简单情况下的线程。我提供以下简化的演示解决方案,其中包含全局变量作为后续开发的起点。

import tkinter
from tkinter import *
from tkinter import ttk
import time

root1 = Tk()

progrBar1 = None  # The main progress bar
win2 = None

def click_but1():
    global win2, progrBar2
    if win2 is None:
        win2 = Toplevel()  # Secondary window
        win2.title('Secondary')
        win2.protocol('WM_DELETE_WINDOW', clickClose)  # close the secondary window on [x] pressing
        but2 = Button(win2, text='Close', command=clickClose)
        but2.pack()
        but3 = Button(win2, text='Process', command=clickProcess)
        but3.pack()
        progrBar2 = ttk.Progressbar(win2, orient = 'horizontal', length = 300, mode = 'determinate')
        progrBar2.pack()
    if progrBar1:
        progrBar1.start(50)

def clickClose():
    global win2
    progrBar1.stop()
    win2.destroy()
    win2=None

def clickProcess():
    my_func()

def my_func():
    global progrBar2
    range1, range2 = 20, 40
    step1 = 100/range1
    for i in range(range1):
        for j in range(range2):
            time.sleep(0.01)
        progrBar2.step(step1)
        root1.update()  # the "update" method

root1.title('Root')  # Main window
progrBar1 = ttk.Progressbar(root1, orient = 'horizontal', mode = 'indeterminate')  # The main progress bar
but1 = Button(root1, text = 'Start', command = click_but1)
but1.pack()
progrBar1.pack()
root1.mainloop()

第一个(主)窗口中的进度条仅在存在辅助窗口时移动。在关闭辅助窗口后,此进度条停止并返回到初始位置。辅助窗口有自己的进度条,用于演示目的,并通过update() 方法显示窗口之间的交互。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    相关资源
    最近更新 更多