你的问题很有趣,但你的方法完全错误。
它首先执行你的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()
链接: