diff --git a/CHANGELOG b/CHANGELOG index 00bea8fe..9ef3f921 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -64,6 +64,7 @@ pyqtgraph-0.9.9 [unreleased] - Fixed MeshData exception caused when vertexes have no matching faces - Fixed GLViewWidget exception handler - Fixed unicode support in Dock + - Fixed PySide crash caused by emitting signal from GraphicsObject.itemChange pyqtgraph-0.9.8 2013-11-24 diff --git a/README.md b/README.md index c2be3fdd..cb79c995 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Contributors * Mattias Põldaru * Thomas S. * Mikhail Terekhov + * fabioz Requirements ------------ diff --git a/pyqtgraph/graphicsItems/GraphicsObject.py b/pyqtgraph/graphicsItems/GraphicsObject.py index 1ea9a08b..015a78c6 100644 --- a/pyqtgraph/graphicsItems/GraphicsObject.py +++ b/pyqtgraph/graphicsItems/GraphicsObject.py @@ -21,8 +21,15 @@ class GraphicsObject(GraphicsItem, QtGui.QGraphicsObject): ret = QtGui.QGraphicsObject.itemChange(self, change, value) if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]: self.parentChanged() - if self.__inform_view_on_changes and change in [self.ItemPositionHasChanged, self.ItemTransformHasChanged]: - self.informViewBoundsChanged() + try: + inform_view_on_change = self.__inform_view_on_changes + except AttributeError: + # It's possible that the attribute was already collected when the itemChange happened + # (if it was triggered during the gc of the object). + pass + else: + if inform_view_on_change and change in [self.ItemPositionHasChanged, self.ItemTransformHasChanged]: + self.informViewBoundsChanged() ## workaround for pyqt bug: ## http://www.riverbankcomputing.com/pipermail/pyqt/2012-August/031818.html diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py index 6bff9c65..58b2aeba 100644 --- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py +++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py @@ -13,20 +13,54 @@ from ... import getConfigOption __all__ = ['ViewBox'] +class WeakList(object): + + def __init__(self): + self._items = [] + + def append(self, obj): + #Add backwards to iterate backwards (to make iterating more efficient on removal). + self._items.insert(0, weakref.ref(obj)) + + def __iter__(self): + i = len(self._items)-1 + while i >= 0: + ref = self._items[i] + d = ref() + if d is None: + del self._items[i] + else: + yield d + i -= 1 class ChildGroup(ItemGroup): - sigItemsChanged = QtCore.Signal() def __init__(self, parent): ItemGroup.__init__(self, parent) + + # Used as callback to inform ViewBox when items are added/removed from + # the group. + # Note 1: We would prefer to override itemChange directly on the + # ViewBox, but this causes crashes on PySide. + # Note 2: We might also like to use a signal rather than this callback + # mechanism, but this causes a different PySide crash. + self.itemsChangedListeners = WeakList() + # excempt from telling view when transform changes self._GraphicsObject__inform_view_on_change = False def itemChange(self, change, value): ret = ItemGroup.itemChange(self, change, value) if change == self.ItemChildAddedChange or change == self.ItemChildRemovedChange: - self.sigItemsChanged.emit() - + try: + itemsChangedListeners = self.itemsChangedListeners + except AttributeError: + # It's possible that the attribute was already collected when the itemChange happened + # (if it was triggered during the gc of the object). + pass + else: + for listener in itemsChangedListeners: + listener.itemsChanged() return ret @@ -140,7 +174,7 @@ class ViewBox(GraphicsWidget): ## this is a workaround for a Qt + OpenGL bug that causes improper clipping ## https://bugreports.qt.nokia.com/browse/QTBUG-23723 self.childGroup = ChildGroup(self) - self.childGroup.sigItemsChanged.connect(self.itemsChanged) + self.childGroup.itemsChangedListeners.append(self) self.background = QtGui.QGraphicsRectItem(self.rect()) self.background.setParentItem(self) @@ -1187,7 +1221,8 @@ class ViewBox(GraphicsWidget): y = tr.y() if mask[1] == 1 else None self._resetTarget() - self.translateBy(x=x, y=y) + if x is not None or y is not None: + self.translateBy(x=x, y=y) self.sigRangeChangedManually.emit(self.state['mouseEnabled']) elif ev.button() & QtCore.Qt.RightButton: #print "vb.rightDrag"