106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
# ============================================
|
|
# =============== 发布/订阅模式 ===============
|
|
# ============================================
|
|
|
|
from PySide2.QtCore import QObject, Slot, Signal, QMutex, QThread, QCoreApplication
|
|
|
|
from umi_log import logger
|
|
|
|
|
|
# 发布/订阅 服务类
|
|
class _PubSubServiceClass:
|
|
def __init__(self):
|
|
# 事件字典,元素为 回调函数列表
|
|
self._eventDict = {}
|
|
self._eventDictMutex = QMutex() # 事件字典的锁
|
|
# 组字典,元素为 组列表。可以成组取消订阅,方便管理。
|
|
self._groupDict = {}
|
|
self._groupDictMutex = QMutex() # 组字典的锁
|
|
# 信号
|
|
self._eventSignal = self._EventSignal()
|
|
self._eventSignal.signal.connect(self._publish)
|
|
|
|
# ========================= 【接口】 =========================
|
|
|
|
# 订阅事件
|
|
def subscribe(self, title, func):
|
|
if not callable(func):
|
|
logger.error(f"订阅事件失败!传入 {func} 不是可调用对象。")
|
|
return
|
|
self._eventDictMutex.lock() # 上锁
|
|
if title not in self._eventDict:
|
|
self._eventDict[title] = [func]
|
|
else:
|
|
self._eventDict[title].append(func)
|
|
self._eventDictMutex.unlock() # 解锁
|
|
|
|
# 订阅事件,可额外传入组名,以便管理。
|
|
def subscribeGroup(self, title, func, groupName):
|
|
self._groupDictMutex.lock() # 上锁
|
|
if groupName not in self._groupDict:
|
|
self._groupDict[groupName] = [(title, func)]
|
|
else:
|
|
self._groupDict[groupName].append((title, func))
|
|
self._groupDictMutex.unlock() # 解锁
|
|
self.subscribe(title, func)
|
|
|
|
# 取消订阅事件
|
|
def unsubscribe(self, title, func):
|
|
if not callable(func):
|
|
logger.error(f"取消订阅事件失败!传入 {func} 不是可调用对象。")
|
|
return
|
|
# 将回调函数从 对应标题的事件列表中 移除
|
|
self._eventDictMutex.lock() # 上锁
|
|
if title in self._eventDict:
|
|
l = self._eventDict[title]
|
|
if func in l:
|
|
l.remove(func)
|
|
self._eventDictMutex.unlock() # 解锁
|
|
|
|
# 取消订阅某个组的所有事件
|
|
def unsubscribeGroup(self, groupName):
|
|
self._groupDictMutex.lock() # 上锁
|
|
if groupName in self._groupDict:
|
|
l = self._groupDict[groupName]
|
|
for i in l:
|
|
self.unsubscribe(i[0], i[1])
|
|
self._groupDict[groupName] = []
|
|
self._groupDictMutex.unlock() # 解锁
|
|
|
|
# 发布事件
|
|
def publish(self, title, *args):
|
|
# 在主线程调用
|
|
if QThread.currentThread() == QCoreApplication.instance().thread():
|
|
self._publish(title, args)
|
|
# 在子线程调用
|
|
else:
|
|
self._eventSignal.signal.emit(title, args)
|
|
|
|
# ========================= 【实现】 =========================
|
|
|
|
# 发布事件的实现(主线程)
|
|
@Slot(str, "QVariant")
|
|
def _publish(self, title, args):
|
|
event_funcs = []
|
|
self._eventDictMutex.lock() # 上锁
|
|
if title in self._eventDict:
|
|
event_funcs = self._eventDict[title].copy() # 拷贝一份
|
|
self._eventDictMutex.unlock() # 解锁
|
|
for func in event_funcs:
|
|
try:
|
|
func(*args)
|
|
except Exception:
|
|
logger.error(
|
|
f"发送事件异常。 title: {title}, args: {args}, func: {func}",
|
|
exc_info=True,
|
|
stack_info=True,
|
|
)
|
|
|
|
# 信号类
|
|
class _EventSignal(QObject):
|
|
signal = Signal(str, "QVariant")
|
|
|
|
|
|
# 发布/订阅 服务单例
|
|
PubSubService = _PubSubServiceClass()
|