大家好,最近在完善手头上一个基于事件系统的 GUI 。

现在遇到一个问题,就是当我在执行一个按钮点击事件的时候,实际会开一个子线程进行业务逻辑的处理,这个处理过程可能会比较长,并且中间可能会出现一些不符合预期的情况发生,当发生这种情况时,我希望会借由发送一个错误的事件通知 EventManager,然后调用 listener 的方法来立刻终结这个对应的错误线程(因为之前已经发生了错误了,后续逻辑代码继续执行没有意义了)

代码如下,大佬们直接复制运行即可观察。如能解答,万分感谢!

from queue import Queue, Empty

from threading import *

from tkinter import *

import time

from tkinter import ttk

EVENT_TYPE_1 = "Count"

EVENT_TYPE_2 = "Error"

MAX_NUMBER = 10

CUR_NUMBER = 0

class event_manager:

def __init__(self):

self._eventQueue = Queue()

self._thread = Thread(target=self.Run, daemon=True)

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

if CUR_NUMBER == 4: # 在业务逻辑线程中增加检测环节,如果发生错误就会发送错误事件,希望可以立刻终结当前的线程,不执行后续的代码

print("************ detect error occurred , this thread should be terminated immediately !")

errorEvent = Event("error", CUR_NUMBER, type_=EVENT_TYPE_2)

self._event_manager.sendEvent(errorEvent)

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.taskThread = None

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)

self.taskThread = Thread(target=es.count, daemon=True).start() # 这里开始执行实际的业务逻辑子线程

def terminate_error_thread(self): # 这个方法在 GUIListener 接受到事件源发出的错误逻辑时被唤起,用来立刻终结正在执行事件源的线程,不做后续无用的代码逻辑处理

pass

# TODO: but how to implement this method ?

if __name__ == '__main__':

gui = GUIListener()

eventMgr = event_manager()

eventMgr.addEventListenter(EVENT_TYPE_1, gui.update_progress_value)

eventMgr.addEventListenter(EVENT_TYPE_2, gui.terminate_error_thread)

eventMgr.Start()

gui.mainloop()

顺便一提,希望得到的结果是这样的

************ 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

************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

************Sub thread start: update progress bar value to...3

************ detect error occurred , this thread should be terminated immediately !

到这里就应该自然停止。

python 事件通知模式_请问在 Python 的事件系统中,如何可以通过事件通知立刻终结一个正在运行的子线程?...相关推荐

  1. python定义数组大小_请问在python数组要先定义长度吗?

    视情况而定 若数组是追加一个元素的可以不用定义长度: 若初始化一个列表然后要修改其中的值的话,就要定义长度了. 例: 拓展资料 设计定位 Python的设计哲学是"优雅".&quo ...

  2. python的out模式_如何用python中的DataFrame列的模式替换NA值?

    我对Python(和本网站)完全陌生,目前正试图用它们的模式替换特定数据帧列中的NA值.我试过了各种不起作用的方法.请帮我看看我做错了什么:如何用python中的DataFrame列的模式替换NA值? ...

  3. python采用函数编程模式_浅谈Python 函数式编程

    匿名函数lambda表达式 什么是匿名函数? 匿名函数,顾名思义就是没有名字的函数,在程序中不用使用 def 进行定义,可以直接使用 lambda 关键字编写简单的代码逻辑.lambda 本质上是一个 ...

  4. python交互编程模式_进入python交互模式的方法

    进入python交互模式的方法 发布时间:2020-08-01 09:57:35 来源:亿速云 阅读:63 作者:清晨 这篇文章主要介绍进入python交互模式的方法,文中介绍的非常详细,具有一定的参 ...

  5. python函数式编程模式_函数式编程指引

    概述¶ 本章介绍函数式编程的基本概念.如您仅想学习 Python 语言的特性,可跳过本章直接查看 迭代器. 编程语言支持通过以下几种方式来解构具体问题: 大多数的编程语言都是 过程式 的,所谓程序就是 ...

  6. python的repl模式_如何更改sublimeREPL默认python版本

    展开全部 stackoverflow上有人提过. In your Packages/User folder, create SublimeREPL/config/Python/Main.sublime ...

  7. python守护线程错误 退出子线程_请问用python里threading和queue模块来写多线程程序,子线程是如何结束的?...

    import queue import threading class Consumer(threading.Thread): def __init__(self, queue): threading ...

  8. python gui开发工具_深入解析Python,透析应用开发,涵盖9大应用领域的Python框架...

    前言 当前,Python 已经成为最流行的程序设计语言之一,被越来越多的人作为首选语言来学习和应用.作为一种解释型的语言,Python具有内置的高级数据结构和简单有效的面向对象编程机制.同时,其语法简 ...

  9. python包括哪些部分_第一部分 Python基础篇

    第⼀一部分 Python基础篇 1. 为什什么学习Python? 朋友推荐,比较简单易学,生态圈比较强大 发展趋势:人工智能.数据分析 2. 通过什什么途径学习的Python? 廖雪峰.网络博客.相关 ...

最新文章

  1. Oracle数据库密码过期重置
  2. Import error: no module named cv2 错误解决方法
  3. python编码格式
  4. 052_Function对象
  5. 二叉树的前序中序后序递归查找,深度,广度搜索C++实现(VS2017)
  6. JAVA基础--final、static区别以及类加载顺序
  7. 如何一次性复制带有markdown/mathjax/latex的博客内容
  8. Exception in thread main java.lang.NoSuchMethodError
  9. Javascript--节点类型
  10. 前端学习(2964):路由的实现
  11. c语言单选题大全,C语言单选题(五)
  12. GMQ交易所正式发布GMQ Token
  13. 设置oracle odbc,Oracle Windows ODBC 数据源配置
  14. stm8L 触摸库使用教程 一步一步
  15. 【游记】CQOI2021
  16. 【JS】V8 引擎原理
  17. 杭电oj刷题(2099)
  18. word2007制作封面、扉页和目录
  19. php mud游戏源码,从零开始构建PHP版mud游戏(三)
  20. 深信服2018校园招聘C++工程师编程题 - 题解

热门文章

  1. python数据库-mysql
  2. html 页面内锚点定位及跳转方法总结
  3. 网站安全--又一种防盗链的措施!
  4. Fedora 18 正式发布
  5. 在OperaMasks中使用ELite和JRuby动态语言的秘笈
  6. 逻辑斯蒂回归(logisic regression)和SVM的异同
  7. c# 对文件的各种操作
  8. [T-ARA][HUE]
  9. 10-Linux 基本指令
  10. JQ中$(window).load和$(document).ready()使用,区别与执行顺序