event.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import abc
  2. import traceback
  3. import threading
  4. import conf
  5. from tool.type_ import *
  6. class TkEventException(Exception):
  7. ...
  8. class TkEventBase(metaclass=abc.ABCMeta):
  9. """
  10. Tkinter 子线程任务
  11. """
  12. def __init__(self):
  13. self.thread: Optional[TkThreading] = None # 子线程
  14. def is_end(self) -> bool: # 判断子线程是否结束
  15. if self.thread is not None and not self.thread.is_alive():
  16. return True
  17. return False
  18. @abc.abstractmethod
  19. def get_title(self) -> str: # 获取任务名字
  20. ...
  21. def done_after_event(self): # 子线程结束后, 在GUI线程执行的代码
  22. if self.thread is not None:
  23. self.thread.wait_event()
  24. class TkEventMain(metaclass=abc.ABCMeta):
  25. """
  26. Tkinter 处理子线程基类
  27. """
  28. def __init__(self):
  29. self._event_list: List[TkEventBase] = []
  30. self.set_after_run(conf.tk_refresh_delay, lambda: self.run_event())
  31. def push_event(self, event: TkEventBase): # 添加子线程
  32. self._event_list.append(event)
  33. self.show_loading(event.get_title())
  34. self.run_event()
  35. def run_event(self): # 定时任务, 检测子线程是否结束, 并运行 done_after_event
  36. if len(self._event_list) == 0:
  37. return
  38. new_event: List[TkEventBase] = []
  39. done_event: List[TkEventBase] = []
  40. for event in self._event_list:
  41. if event.is_end():
  42. done_event.append(event)
  43. else:
  44. new_event.append(event)
  45. self._event_list = new_event
  46. if len(self._event_list) == 0:
  47. self.stop_loading()
  48. for event in done_event: # 隐藏进度条后执行Event-GUI任务
  49. try:
  50. event.done_after_event()
  51. except:
  52. traceback.print_exc()
  53. self.set_after_run_now(conf.tk_refresh_delay, self.run_event)
  54. @abc.abstractmethod
  55. def show_loading(self, title: str): # 有子线程时显示加载
  56. ...
  57. @abc.abstractmethod
  58. def stop_loading(self): # 子线程运行完成后关闭加载
  59. ...
  60. @abc.abstractmethod
  61. def set_after_run(self, ms, func, *args):
  62. ...
  63. @abc.abstractmethod
  64. def set_after_run_now(self, ms, func, *args):
  65. ...
  66. class TkThreading(threading.Thread):
  67. """
  68. tkinter 子线程
  69. """
  70. def __init__(self, func, *args, start_now: bool = True):
  71. """
  72. :param func: 子线程函数
  73. :param args: 子线程参数
  74. :param start_now: 是否马上运行 (否则要回调.start函数)
  75. """
  76. threading.Thread.__init__(self)
  77. self.func = func
  78. self.args = args
  79. self.result = None
  80. if start_now:
  81. self.start()
  82. def run(self):
  83. try:
  84. self.result = self.func(*self.args)
  85. except:
  86. traceback.print_exc()
  87. finally:
  88. del self.func, self.args
  89. def wait_event(self) -> any:
  90. """
  91. 等待线程结束
  92. :return: 线程函数的返回值
  93. """
  94. self.join()
  95. return self.result