Python Tkinter:调用函数时更新progressbar

Python Tkinter:调用函数时更新progressbar,python,python-3.x,tkinter,python-3.6,Python,Python 3.x,Tkinter,Python 3.6,想象一下以下简单的例子: def doNothing(): sleep(0.5) barVar.set(10) sleep(0.5) barVar.set(20) sleep(0.5) barVar.set(30) mainWindow = Tk() barVar = DoubleVar() barVar.set(0) bar = Progressbar(mainWindow, length=200, style='black.Horizontal.TProgressb

想象一下以下简单的例子:

def doNothing():
  sleep(0.5)
  barVar.set(10)
  sleep(0.5)
  barVar.set(20)
  sleep(0.5)
  barVar.set(30)

mainWindow = Tk()
barVar = DoubleVar()
barVar.set(0)
bar = Progressbar(mainWindow, length=200, style='black.Horizontal.TProgressbar', variable=barVar, mode='determinate')
bar.grid(row=1, column=0)
button= Button(mainWindow, text='Click', command=doNothing)
button.grid(row=0, column=0)
mainWindow.mainloop()
我得到的当我运行此操作时,当单击按钮时,进度条已达到30%,我面前没有进度。类似附件:

我需要什么:我可以看到我面前的进步(不挂然后突然30%)

更新: 我根据@Bernhard-answer更新了代码,但仍然看不到前面的进度。在等待1.5秒后突然跳了30%

Seocnd更新:
在这里,我只是使用sleep来模拟一个需要时间的过程,比如通过ssh连接并获取一些信息。

因为在初始化接口时调用函数,所以需要在命令=(barVar)中释放“(barVar”)。通过这种方式,您可以将函数绑定到按钮,并且在初始化时不调用它

button= Button(mainWindow, text='Click', command=doNothing)
如果需要传递参数,则需要使用lambda绕过调用:

button= Button(mainWindow, text='Click', command= lambda: doNothing(barVar))

我想我找到了解决办法

只需在每次进度后添加
mainWindow.update()
。因此,最终的代码是:

def doNothing():
  sleep(0.5)
  barVar.set(10)
  mainWindow.update()
  sleep(0.5)
  barVar.set(20)
  mainWindow.update()
  sleep(0.5)
  barVar.set(30)
  mainWindow.update()
不要在tkinter中使用
sleep()
。您出现问题的全部原因是
sleep()
将冻结tkinter,直到它完成计数,因此您看到的是一个冻结的程序,当程序最终释放时,它在下一次主循环更新时已设置为30%

相反,我们需要使用Tkinter的内置方法
after()
,因为after专门用于此目的

将tkinter作为tk导入 将tkinter.ttk导入为ttk

mainWindow = tk.Tk()

def update_progress_bar():
    x = barVar.get()
    if x < 100:
        barVar.set(x+10)
        mainWindow.after(500, update_progress_bar)
    else:
        print("Complete")


barVar = tk.DoubleVar()
barVar.set(0)
bar = ttk.Progressbar(mainWindow, length=200, style='black.Horizontal.TProgressbar', variable=barVar, mode='determinate')
bar.grid(row=1, column=0)
button= tk.Button(mainWindow, text='Click', command=update_progress_bar)
button.grid(row=0, column=0)

mainWindow.mainloop()
mainWindow=tk.tk()
def更新进度条():
x=barVar.get()
如果x<100:
巴伐尔集(x+10)
主窗口。之后(500,更新进度条)
其他:
打印(“完成”)
barVar=tk.DoubleVar()
barVar.set(0)
bar=ttk.Progressbar(主窗口,长度=200,style='black.Horizontal.TProgressbar',变量=barVar,模式='definite')
条形网格(行=1,列=0)
button=tk.button(主窗口,text='Click',command=update\u progress\u bar)
button.grid(行=0,列=0)
mainWindow.mainloop()
如果您希望条显示为平滑移动,则需要加快函数调用并减少对DoubbleVar的添加

import tkinter as tk
import tkinter.ttk as ttk


mainWindow = tk.Tk()

def update_progress_bar():
    x = barVar.get()
    if x < 100:
        barVar.set(x+0.5)
        mainWindow.after(50, update_progress_bar)
    else:
        print("Complete")


barVar = tk.DoubleVar()
barVar.set(0)
bar = ttk.Progressbar(mainWindow, length=200, style='black.Horizontal.TProgressbar', variable=barVar, mode='determinate')
bar.grid(row=1, column=0)
button= tk.Button(mainWindow, text='Click', command=update_progress_bar)
button.grid(row=0, column=0)

mainWindow.mainloop()
将tkinter作为tk导入
将tkinter.ttk导入为ttk
mainWindow=tk.tk()
def更新进度条():
x=barVar.get()
如果x<100:
巴伐尔集(x+0.5)
主窗口。之后(50,更新进度条)
其他:
打印(“完成”)
barVar=tk.DoubleVar()
barVar.set(0)
bar=ttk.Progressbar(主窗口,长度=200,style='black.Horizontal.TProgressbar',变量=barVar,模式='definite')
条形网格(行=1,列=0)
button=tk.button(主窗口,text='Click',command=update\u progress\u bar)
button.grid(行=0,列=0)
mainWindow.mainloop()

谢谢您的回答。我进行了相应的更新,但仍然存在看不到进度的问题。这可能对纠正很重要,但这不是OP的问题。千万不要将
sleep()
与tkinter一起使用。sleep只是冻结tkinter实例,因为tkinter是单线程程序。请改用名为
after()
的内置tkinter方法。谢谢您的回答。但我只是添加睡眠来模拟需要时间的过程。。。就像连接到远程服务器并获取一些信息一样,如果您的答案不起作用,progressbar将被挂起,直到1.5秒睡眠时间过去。我希望看到每0.5秒后的进度,正如在使用睡眠之前提到的,这里必须模拟长时间睡眠process@AhmedWas然后,您的问题就出现在代码中的其他地方,或者从中获得进展。您不能出于任何原因在tkinter中使用sleep。它就是不起作用。因此,请使用可以使用相同结果进行测试的内容更新您的代码。在我这方面,我的代码工作得很好,所以在你这方面,有些东西是错误的。在代码中是否有其他位置的睡眠?您正在导入一些使用睡眠的方法吗?你的进度条到底是什么?@但为什么你认为mainWindow.update()是个糟糕的解决方案?我的意思是,它对我来说工作得很好。@AhmedWas因为不需要
update()
函数,因为所有更新都发生在每个事件循环的主循环中<代码>睡眠()在这里使用是100%错误的。这段代码的问题在于你没有解决真正的问题,而是使用了一个糟糕的解决方法来可视化加载条的更新。tkinter应用程序仍处于冻结状态,在这些睡眠调用期间不可用。在任何情况下,您的程序中都不应该有专门冻结GUI的代码,这可能会导致不可预测的问题。@Mike SMT您提到Tkinter应用程序已冻结,不适合在睡眠呼叫期间使用。。。这是不对的。应用程序未冻结,您可以单击按钮,通话将从头开始。我的意思是,如果你在sleep call中单击按钮,你会看到progressbar从头开始,这里有无数关于sleep和tkinter的帖子和文档。除非在单独的线程中使用线程和运行sleep,否则sleep实际上会冻结tkinter实例,直到睡眠完成。