diff options
Diffstat (limited to 'silx/gui/plot/utils/axis.py')
-rw-r--r-- | silx/gui/plot/utils/axis.py | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/silx/gui/plot/utils/axis.py b/silx/gui/plot/utils/axis.py index f7ec711..80e1dc4 100644 --- a/silx/gui/plot/utils/axis.py +++ b/silx/gui/plot/utils/axis.py @@ -27,12 +27,13 @@ __authors__ = ["V. Valls"] __license__ = "MIT" -__date__ = "04/08/2017" +__date__ = "23/02/2018" import functools import logging from contextlib import contextmanager -from silx.utils import weakref +import weakref +import silx.utils.weakref as silxWeakref _logger = logging.getLogger(__name__) @@ -63,14 +64,20 @@ class SyncAxes(object): :param bool syncDirection: Synchronize axes direction """ object.__init__(self) - self.__axes = [] self.__locked = False + self.__axes = [] self.__syncLimits = syncLimits self.__syncScale = syncScale self.__syncDirection = syncDirection - self.__callbacks = [] + self.__callbacks = None + + qtCallback = silxWeakref.WeakMethodProxy(self.__deleteAxisQt) + for axis in axes: + ref = weakref.ref(axis) + self.__axes.append(ref) + callback = functools.partial(qtCallback, ref) + axis.destroyed.connect(callback) - self.__axes.extend(axes) self.start() def start(self): @@ -80,54 +87,71 @@ class SyncAxes(object): After that, any changes to any axes will be used to synchronize other axes. """ - if len(self.__callbacks) != 0: + if self.__callbacks is not None: raise RuntimeError("Axes already synchronized") + self.__callbacks = {} # register callback for further sync - for axis in self.__axes: + for refAxis in self.__axes: + axis = refAxis() + callbacks = [] if self.__syncLimits: # the weakref is needed to be able ignore self references - callback = weakref.WeakMethodProxy(self.__axisLimitsChanged) - callback = functools.partial(callback, axis) + callback = silxWeakref.WeakMethodProxy(self.__axisLimitsChanged) + callback = functools.partial(callback, refAxis) sig = axis.sigLimitsChanged sig.connect(callback) - self.__callbacks.append((sig, callback)) + callbacks.append(("sigLimitsChanged", callback)) if self.__syncScale: # the weakref is needed to be able ignore self references - callback = weakref.WeakMethodProxy(self.__axisScaleChanged) - callback = functools.partial(callback, axis) + callback = silxWeakref.WeakMethodProxy(self.__axisScaleChanged) + callback = functools.partial(callback, refAxis) sig = axis.sigScaleChanged sig.connect(callback) - self.__callbacks.append((sig, callback)) + callbacks.append(("sigScaleChanged", callback)) if self.__syncDirection: # the weakref is needed to be able ignore self references - callback = weakref.WeakMethodProxy(self.__axisInvertedChanged) - callback = functools.partial(callback, axis) + callback = silxWeakref.WeakMethodProxy(self.__axisInvertedChanged) + callback = functools.partial(callback, refAxis) sig = axis.sigInvertedChanged sig.connect(callback) - self.__callbacks.append((sig, callback)) + callbacks.append(("sigInvertedChanged", callback)) + + self.__callbacks[refAxis] = callbacks # sync the current state - mainAxis = self.__axes[0] + refMainAxis = self.__axes[0] + mainAxis = refMainAxis() if self.__syncLimits: - self.__axisLimitsChanged(mainAxis, *mainAxis.getLimits()) + self.__axisLimitsChanged(refMainAxis, *mainAxis.getLimits()) if self.__syncScale: - self.__axisScaleChanged(mainAxis, mainAxis.getScale()) + self.__axisScaleChanged(refMainAxis, mainAxis.getScale()) if self.__syncDirection: - self.__axisInvertedChanged(mainAxis, mainAxis.isInverted()) + self.__axisInvertedChanged(refMainAxis, mainAxis.isInverted()) + + def __deleteAxis(self, ref): + _logger.debug("Delete axes ref %s", ref) + self.__axes.remove(ref) + del self.__callbacks[ref] + + def __deleteAxisQt(self, ref, qobject): + self.__deleteAxis(ref) def stop(self): """Stop the synchronization of the axes""" - if len(self.__callbacks) == 0: + if self.__callbacks is None: raise RuntimeError("Axes not synchronized") - for sig, callback in self.__callbacks: - sig.disconnect(callback) - self.__callbacks = [] + for ref, callbacks in self.__callbacks.items(): + axes = ref() + for sigName, callback in callbacks: + sig = getattr(axes, sigName) + sig.disconnect(callback) + self.__callbacks = None def __del__(self): """Destructor""" # clean up references - if len(self.__callbacks) != 0: + if self.__callbacks is not None: self.stop() @contextmanager @@ -138,6 +162,7 @@ class SyncAxes(object): def __otherAxes(self, changedAxis): for axis in self.__axes: + axis = axis() if axis is changedAxis: continue yield axis @@ -145,6 +170,7 @@ class SyncAxes(object): def __axisLimitsChanged(self, changedAxis, vmin, vmax): if self.__locked: return + changedAxis = changedAxis() with self.__inhibitSignals(): for axis in self.__otherAxes(changedAxis): axis.setLimits(vmin, vmax) @@ -152,6 +178,7 @@ class SyncAxes(object): def __axisScaleChanged(self, changedAxis, scale): if self.__locked: return + changedAxis = changedAxis() with self.__inhibitSignals(): for axis in self.__otherAxes(changedAxis): axis.setScale(scale) @@ -159,6 +186,7 @@ class SyncAxes(object): def __axisInvertedChanged(self, changedAxis, isInverted): if self.__locked: return + changedAxis = changedAxis() with self.__inhibitSignals(): for axis in self.__otherAxes(changedAxis): axis.setInverted(isInverted) |