import sys
import ttk
from Tkinter import *
from timeit import default_timer as timer
def sum(a, b):
for i in range(10):
c = a + b
print "Sum", c
time.sleep(5)
return c
mGui = Tk()
mGui.title('Progress')
mpb = ttk.Progressbar(mGui,orient ="horizontal", length = 200, mode ="determinate")
mpb.pack()
mpb.start()
mpb["maximum"] = 100
Start_Timer=timer()
sum(3,4)
Stop_Timer=timer()
Execution_Time=Stop_Timer-Start_Timer
mpb["value"] = Execution_Time
mGui.mainloop()
我有一个计算两个整数之和的函数。我想使用tkinter进度条显示此sum函数的执行状态。
这是我的方法,但它在执行sum
函数后显示进度条,我想在sum
函数执行时显示进度条,并且应该根据函数的执行时间。
我找不到符合我要求的答案。如果有人可以帮助我,那就太好了。
答案 0 :(得分:1)
你的问题很有意思,但你接近是完全错误的。
它首先执行sum
,因为GUI尚未到达mainloop
。
因此,在GUI到达mainloop
之后,它开始等待按钮按下事件(因为GUI编程的事件驱动性质)。换句话说:如果你要求回调tkinter,你就不能在mainloop
之前调用函数。
另一个问题 - tkinter是单线程的,因此gui只能在函数完成运行时自行更新。因此,如果你在函数中启动一个循环,那么gui也没有回调函数,但是你可以从循环中调用函数,并在每次迭代时更新gui! (例如,自生成事件的“循环”,由方法generate_event
或after
组成。)
为了上帝的缘故,如果函数没有完全执行,进度条如何知道函数的执行时间?如果有人知道,请发表评论..
但是如果你敢,你可以开始玩多线程和队列了!
在我的示例中,进度条与函数的执行并行更新,这要归功于执行函数的单独线程,以及函数“响应”所依赖的队列,在此基础上进度条正在更新!
使用python 3.5进行测试:
try:
import Tkinter as tk # Python 2
import ttk
import Queue as queue
except ImportError:
import tkinter as tk # Python 3
import tkinter.ttk as ttk
import queue
import threading
import time
class ThreadFunc(threading.Thread):
def __init__(self, loop_time=1.0 / 60):
super(ThreadFunc, self).__init__()
self.queue = queue.Queue()
self.timeout = loop_time
self.parent = None
self.stop_on_complete = None
self.running = False
self._stop = threading.Event()
def start_thread(self, parent, stop_on_complete=False):
# thread can wait for functions if not stop_on_complete
self.parent = parent
self.stop_on_complete = stop_on_complete
self.running = True
self.start()
def put_function(self, function, *args, **kwargs):
# put another function in queue
self.queue.put((function, args, kwargs))
def run(self):
print('### STARTED ###')
while self.running:
try:
function, args, kwargs = self.queue.get(timeout=self.timeout)
print('### RUNNING ###')
function(*args, **kwargs)
except queue.Empty:
if self.stop_on_complete:
self.stop()
else:
self.idle()
def stop(self):
print('### STOPPED ###')
self.running = False
self._stop.set()
@staticmethod
def idle():
print('### IDLE ###')
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.resizable(width=False, height=False)
self.minsize(width=400, height=25)
self.wm_title('Another SO Example with progressbar')
self.queue = queue.Queue()
self.thread = None
self.in_work = False
self.mpb_frame = tk.Frame(self)
self.mpb = ttk.Progressbar(self.mpb_frame, orient='horizontal', length=400, mode='determinate')
self.mpb.pack()
self.mpb_frame.pack()
self.mpb.bind('<Map>', self.start_example)
def start_example(self, event=None):
if self.in_work:
return
self.in_work = True
self.spawn_thread(sum_func, 4, 3, self.queue)
def spawn_thread(self, command, *args):
# spawn a thread
self.thread = ThreadFunc()
self.thread.start_thread(self, True)
self.thread.put_function(command, *args)
self.periodic_call()
def periodic_call(self):
# check if our thread is running and if so - update progressbar
self.check_queue()
try:
self.thread.is_alive()
self.after(100, self.periodic_call)
except TypeError:
self.in_work = False
self.quit()
def check_queue(self):
# "transfer" messages to mpb-progressbar steps (10 iteration over you sum)
while self.queue.qsize():
try:
self.queue.get(0)
self.mpb.step(10)
except queue.Empty:
pass
def sum_func(a, b, queue_local):
# your sum function
for i in range(10):
c = a + b
time.sleep(1)
queue_local.put(c)
print('Sum', c)
app = App()
app.mainloop()
链接: