我正在开发一个提供图表网格的Qt小部件(每个都是一个QWidget)。我想在所有情节上同步“keepAspectRatio”政策。
如果我调用sigKeepAspectRatioChanged
方法广播政策(setKeepDataAspectRatio(bool)
或True
)及其False
,则每个单独的地图都会发出(row, column)
信号网格中的坐标。
我的复合小部件会侦听其所有图,当其中一个更改其宽高比策略(单击工具按钮)时,它需要将其传播到所有其他图。
这是我尝试过的,但它会导致无数RuntimeError: maximum recursion depth exceeded in cmp
个错误:
def _onKeepAspectRatioChanged(self, isKeepAspectRatio, row, col):
"""If any plot changes its keepAspectRatio policy,
apply it to all other plots."""
print("received sigKeepAspectRatioChanged from plot %d, %d" % (row, col))
self.blockSignals(True)
for r, c in self._plots:
if not (r, c) == (row, col):
self._plots[(r, c)].plot.setKeepDataAspectRatio(isKeepAspectRatio)
qt.QApplication.instance().processEvents()
self.blockSignals(False)
有关如何正确执行此操作的任何想法?
顺便说一下,对每个单独情节的引用都保存在字典中(self. _plots
),而dict键是(r, c)
坐标元组。
答案 0 :(得分:2)
您真正关心的是该方法未重新输入。信号和插槽只是它发生的渠道。因此:保护相关方法免于递归。它比断开和恢复信号槽连接效率高出一个数量级。基本上:
def _method(self, ...):
if self.in_method:
return
try:
self.in_method = True
...
finally:
self.in_method = False
这当然可以包装在装饰者中:
@norecursion
def _onKeepAspectRatioChanged(self, isKeepAspectRatio, row, col):
...
来自this blog post的装饰者:
def norecursion(default=None):
'''Prevents recursion into the wrapped function.'''
def entangle(f):
def inner(*args, **kwds):
if not hasattr(f, 'callcount'):
f.callcount = 0
if f.callcount >= 1:
return default
else:
f.callcount += 1
x = f(*args, **kwds)
f.callcount -= 1
return x
return inner
return entangle
答案 1 :(得分:0)
我找到了一个有效的解决方案,但它可能不是最有效的解决方案:我断开所有单独的信号,然后在设置所有策略后重新连接。
def _onKeepAspectRatioChanged(self, isKeepAspectRatio, row, col):
with self._disconnectAllAspectRatioSignals():
for r, c in self._plots:
self._plots[(r, c)].plot.setKeepDataAspectRatio(isKeepAspectRatio)
@contextlib.contextmanager
def _disconnectAllAspectRatioSignals(self):
for r, c in self._plots:
self._plots[(r, c)].sigKeepAspectRatioChanged.disconnect(
self._onKeepAspectRatioChanged)
yield
for r, c in self._plots:
self._plots[(r, c)].sigKeepAspectRatioChanged.connect(
self._onKeepAspectRatioChanged)