利用线程和事件系统更新 tkinter 的进度条,在同步的时候卡住了,求大佬帮看下。。。
最近在用 python 写工具给小组的其他成员使用,因为需要可以在 GUI 上输入不同的变量值做不同的判断处理所以最后写了一个 gui 。现在问题是,最后我希望写一个进度条,可以在主线程的 for-loop 中,每处理完一个任务后发送一个事件,给在另外一个线程的事件管理器,事件管理器可以立刻更新响应 GUI 的进度条的进度。 下面是我写的代码:
from queue import Queue, Empty from threading import * from tkinter import * import time from tkinter import ttk EVENT_TYPE_1 = "Count" MAX_NUMBER = 10 CUR_NUMBER = 0 class event_manager: def __init__(self): self._eventQueue = Queue() self._thread = Thread(target=self.Run) self._handlers = {} self._active = False def Start(self): self._active = True self._thread.start() def Run(self): while self._active is True: try: event = self._eventQueue.get(block=True, timeout=1) self.Process(event) except Empty: pass def Process(self, event): if event.type in self._handlers: for handler in self._handlers[event.type]: handler() else: pass def Stop(self): self._active = False self._thread.join() def addEventListenter(self, type_, handler): try: handlerList = self._handlers[type_] except KeyError: handlerList = [] self._handlers[type_] = handlerList if handler not in handlerList: handlerList.append(handler) def removeEventListenter(self, type_, handler): try: handlerList = self._handlers[type_] if handler in handlerList: handlerList.remove(handler) if not handlerList: del self._handlers[type_] except KeyError: pass def sendEvent(self, event): self._eventQueue.put(event) class Event: def __init__(self, event_event_name, cur_done_task, type_=None): self.type = type_ self._event_name = event_event_name self._curDoneTask = cur_done_task class EventSource: def __init__(self, event_name, event_mgr, max_number, type): self._event_name = event_name self._event_manager = event_mgr self._type = type self._max_number = max_number def count(self): global CUR_NUMBER for i in range(self._max_number): CUR_NUMBER = i + 1 print("************ main thread start:now start process {} - count : {}".format(self._event_name, CUR_NUMBER)) event = Event("test", CUR_NUMBER, type_=self._type) self._event_manager.sendEvent(event) time.sleep(1) class GUIListener(Tk): def __init__(self): super(GUIListener, self).__init__() self.title("Progress GUI") self.geometry("1200x805+600+100") self.config(bg="#535353") self.resizable(True, True) self.progressBar = ttk.Progressbar(master=self, orient=HORIZONTAL, maximum=MAX_NUMBER, length=300) self.progressBar.pack() self.button = ttk.Button(self, text="Run", command=lambda: self.button_function(MAX_NUMBER)) self.button.pack() def update_progress_value(self): print("************Sub thread start: detect progress bar value is now...{}".format(self.progressBar['value'])) self.progressBar['value'] = CUR_NUMBER self.progressBar.update_idletasks() print("************Sub thread start: update progress bar value to...{}".format(CUR_NUMBER)) def button_function(self,max_number): es = EventSource("eventSource", eventMgr, max_number, EVENT_TYPE_1) es.count() if __name__ == '__main__': gui = GUIListener() eventMgr = event_manager() eventMgr.addEventListenter(EVENT_TYPE_1, gui.update_progress_value) eventMgr.Start() gui.mainloop()
现在的问题是,返回的结果很奇怪,是这样的:
************ main thread start:now start process eventSource - count : 1 ************ main thread start:now start process eventSource - count : 2 ************ main thread start:now start process eventSource - count : 3 ************ main thread start:now start process eventSource - count : 4 ************ main thread start:now start process eventSource - count : 5 ************ main thread start:now start process eventSource - count : 6 ************ main thread start:now start process eventSource - count : 7 ************ main thread start:now start process eventSource - count : 8 ************ main thread start:now start process eventSource - count : 9 ************ main thread start:now start process eventSource - count : 10 ************Sub thread start: detect progress bar value is now...0.0 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10 ************Sub thread start: detect progress bar value is now...10 ************Sub thread start: update progress bar value to...10
请大佬指点一下,因为我希望的结果是类似下面这样立刻响应插入的顺序:
************ main thread start:now start process eventSource - count : 1 ************Sub thread start: detect progress bar value is now...0.0 ************Sub thread start: update progress bar value to...1 ************ main thread start:now start process eventSource - count : 2 ************Sub thread start: detect progress bar value is now...1.0 ************Sub thread start: update progress bar value to...2 ************ main thread start:now start process eventSource - count : 3 ************Sub thread start: detect progress bar value is now...2.0 ************Sub thread start: update progress bar value to...3 ... etc
真的这个问题困扰了我蛮久了,希望大佬可以不吝赐教,指点问题发生在哪里,如何修改可以达到预期目的,感激不尽!