diff --git a/CHANGELOG b/CHANGELOG index 81e384ee68aba7b509949790708d4f624b01fb1f..ec55856455ca284aabd2f1710d9aab7a77a766eb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,9 @@ pyqtgraph-0.9.9 [unreleased] - ImageItem is faster by avoiding makeQImage(transpose=True) - ComboBox will raise error when adding multiple items of the same name - ArrowItem.setStyle now updates style options rather than replacing them + - Renamed GraphicsView signals to avoid collision with ViewBox signals that + are wrapped in PlotWidget: sigRangeChanged => sigDeviceRangeChanged and + sigTransformChanged => sigDeviceTransformChanged. New Features: - Added ViewBox.setLimits() method diff --git a/pyqtgraph/flowchart/Flowchart.py b/pyqtgraph/flowchart/Flowchart.py index 27586040e4c6d88fc3f3933bda74bfae4a37249a..48357b30a99261fcc7321476578ddaeb4abd8744 100644 --- a/pyqtgraph/flowchart/Flowchart.py +++ b/pyqtgraph/flowchart/Flowchart.py @@ -227,18 +227,11 @@ class Flowchart(Node): def nodeClosed(self, node): del self._nodes[node.name()] self.widget().removeNode(node) - try: - node.sigClosed.disconnect(self.nodeClosed) - except TypeError: - pass - try: - node.sigRenamed.disconnect(self.nodeRenamed) - except TypeError: - pass - try: - node.sigOutputChanged.disconnect(self.nodeOutputChanged) - except TypeError: - pass + for signal in ['sigClosed', 'sigRenamed', 'sigOutputChanged']: + try: + getattr(node, signal).disconnect(self.nodeClosed) + except (TypeError, RuntimeError): + pass self.sigChartChanged.emit(self, 'remove', node) def nodeRenamed(self, node, oldName): @@ -769,7 +762,7 @@ class FlowchartCtrlWidget(QtGui.QWidget): #self.disconnect(item.bypassBtn, QtCore.SIGNAL('clicked()'), self.bypassClicked) try: item.bypassBtn.clicked.disconnect(self.bypassClicked) - except TypeError: + except (TypeError, RuntimeError): pass self.ui.ctrlList.removeTopLevelItem(item) diff --git a/pyqtgraph/graphicsItems/FillBetweenItem.py b/pyqtgraph/graphicsItems/FillBetweenItem.py index 3cf33acdc976738b86bd66e2606d87543261d10b..d2ee393c44e4a2d8baaf332d266732b811d9b46d 100644 --- a/pyqtgraph/graphicsItems/FillBetweenItem.py +++ b/pyqtgraph/graphicsItems/FillBetweenItem.py @@ -28,7 +28,7 @@ class FillBetweenItem(QtGui.QGraphicsPathItem): for c in self.curves: try: c.sigPlotChanged.disconnect(self.curveChanged) - except TypeError: + except (TypeError, RuntimeError): pass curves = [curve1, curve2] diff --git a/pyqtgraph/graphicsItems/GraphicsItem.py b/pyqtgraph/graphicsItems/GraphicsItem.py index 8d2238b8c11fcf732d42ccb088c2dc9accc414b8..e34086bdb0e6529fef3902592042809ffd219130 100644 --- a/pyqtgraph/graphicsItems/GraphicsItem.py +++ b/pyqtgraph/graphicsItems/GraphicsItem.py @@ -479,24 +479,29 @@ class GraphicsItem(object): ## disconnect from previous view if oldView is not None: - #print "disconnect:", self, oldView - try: - oldView.sigRangeChanged.disconnect(self.viewRangeChanged) - except TypeError: - pass - - try: - oldView.sigTransformChanged.disconnect(self.viewTransformChanged) - except TypeError: - pass + for signal, slot in [('sigRangeChanged', self.viewRangeChanged), + ('sigDeviceRangeChanged', self.viewRangeChanged), + ('sigTransformChanged', self.viewTransformChanged), + ('sigDeviceTransformChanged', self.viewTransformChanged)]: + try: + getattr(oldView, signal).disconnect(slot) + except (TypeError, AttributeError, RuntimeError): + # TypeError and RuntimeError are from pyqt and pyside, respectively + pass self._connectedView = None ## connect to new view if view is not None: #print "connect:", self, view - view.sigRangeChanged.connect(self.viewRangeChanged) - view.sigTransformChanged.connect(self.viewTransformChanged) + if hasattr(view, 'sigDeviceRangeChanged'): + # connect signals from GraphicsView + view.sigDeviceRangeChanged.connect(self.viewRangeChanged) + view.sigDeviceTransformChanged.connect(self.viewTransformChanged) + else: + # connect signals from ViewBox + view.sigRangeChanged.connect(self.viewRangeChanged) + view.sigTransformChanged.connect(self.viewTransformChanged) self._connectedView = weakref.ref(view) self.viewRangeChanged() self.viewTransformChanged() diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py index 9d0c32405590b549c0d3ae65f1ec9a7e1c2490c5..632e7cdf132c39b490e05d710925ad91d53d499f 100644 --- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py +++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py @@ -881,7 +881,7 @@ class ViewBox(GraphicsWidget): try: getattr(oldLink, signal).disconnect(slot) oldLink.sigResized.disconnect(slot) - except TypeError: + except (TypeError, RuntimeError): ## This can occur if the view has been deleted already pass diff --git a/pyqtgraph/graphicsWindows.py b/pyqtgraph/graphicsWindows.py index 6e7d630516302e8afbb75b92b3d28206df20dec5..1aa3f3f4d6d47d3efe7e5625b76a23454b7e1417 100644 --- a/pyqtgraph/graphicsWindows.py +++ b/pyqtgraph/graphicsWindows.py @@ -19,11 +19,14 @@ def mkQApp(): class GraphicsWindow(GraphicsLayoutWidget): + """ + Convenience subclass of :class:`GraphicsLayoutWidget + <pyqtgraph.GraphicsLayoutWidget>`. This class is intended for use from + the interactive python prompt. + """ def __init__(self, title=None, size=(800,600), **kargs): mkQApp() - #self.win = QtGui.QMainWindow() GraphicsLayoutWidget.__init__(self, **kargs) - #self.win.setCentralWidget(self) self.resize(*size) if title is not None: self.setWindowTitle(title) diff --git a/pyqtgraph/parametertree/Parameter.py b/pyqtgraph/parametertree/Parameter.py index c62432f2fa92ed1392bd037791628e2d79f44e87..f7cb42a0bdaa6811134745bf4cc1774501316e2c 100644 --- a/pyqtgraph/parametertree/Parameter.py +++ b/pyqtgraph/parametertree/Parameter.py @@ -516,7 +516,7 @@ class Parameter(QtCore.QObject): self.sigChildRemoved.emit(self, child) try: child.sigTreeStateChanged.disconnect(self.treeStateChanged) - except TypeError: ## already disconnected + except (TypeError, RuntimeError): ## already disconnected pass def clearChildren(self): diff --git a/pyqtgraph/widgets/GraphicsLayoutWidget.py b/pyqtgraph/widgets/GraphicsLayoutWidget.py index 3c34ca58ab8247836d9b68b6c2e667a60f9bf23d..ec7b9e0d763d3f3512492812c3d4a1e0abf9ff52 100644 --- a/pyqtgraph/widgets/GraphicsLayoutWidget.py +++ b/pyqtgraph/widgets/GraphicsLayoutWidget.py @@ -4,9 +4,27 @@ from .GraphicsView import GraphicsView __all__ = ['GraphicsLayoutWidget'] class GraphicsLayoutWidget(GraphicsView): + """ + Convenience class consisting of a :class:`GraphicsView + <pyqtgraph.GraphicsView>` with a single :class:`GraphicsLayout + <pyqtgraph.GraphicsLayout>` as its central item. + + This class wraps several methods from its internal GraphicsLayout: + :func:`nextRow <pyqtgraph.GraphicsLayout.nextRow>` + :func:`nextColumn <pyqtgraph.GraphicsLayout.nextColumn>` + :func:`addPlot <pyqtgraph.GraphicsLayout.addPlot>` + :func:`addViewBox <pyqtgraph.GraphicsLayout.addViewBox>` + :func:`addItem <pyqtgraph.GraphicsLayout.addItem>` + :func:`getItem <pyqtgraph.GraphicsLayout.getItem>` + :func:`addLabel <pyqtgraph.GraphicsLayout.addLabel>` + :func:`addLayout <pyqtgraph.GraphicsLayout.addLayout>` + :func:`removeItem <pyqtgraph.GraphicsLayout.removeItem>` + :func:`itemIndex <pyqtgraph.GraphicsLayout.itemIndex>` + :func:`clear <pyqtgraph.GraphicsLayout.clear>` + """ def __init__(self, parent=None, **kargs): GraphicsView.__init__(self, parent) self.ci = GraphicsLayout(**kargs) - for n in ['nextRow', 'nextCol', 'nextColumn', 'addPlot', 'addViewBox', 'addItem', 'getItem', 'addLabel', 'addLayout', 'addLabel', 'addViewBox', 'removeItem', 'itemIndex', 'clear']: + for n in ['nextRow', 'nextCol', 'nextColumn', 'addPlot', 'addViewBox', 'addItem', 'getItem', 'addLayout', 'addLabel', 'removeItem', 'itemIndex', 'clear']: setattr(self, n, getattr(self.ci, n)) self.setCentralItem(self.ci) diff --git a/pyqtgraph/widgets/GraphicsView.py b/pyqtgraph/widgets/GraphicsView.py index 70472fd3f0c1bcac1a65b918462eae8366f9d84e..649a5ec81d0d5fa6dad395f2b7ed18e68a91829e 100644 --- a/pyqtgraph/widgets/GraphicsView.py +++ b/pyqtgraph/widgets/GraphicsView.py @@ -40,8 +40,8 @@ class GraphicsView(QtGui.QGraphicsView): The view can be panned using the middle mouse button and scaled using the right mouse button if enabled via enableMouse() (but ordinarily, we use ViewBox for this functionality).""" - sigRangeChanged = QtCore.Signal(object, object) - sigTransformChanged = QtCore.Signal(object) + sigDeviceRangeChanged = QtCore.Signal(object, object) + sigDeviceTransformChanged = QtCore.Signal(object) sigMouseReleased = QtCore.Signal(object) sigSceneMouseMoved = QtCore.Signal(object) #sigRegionChanged = QtCore.Signal(object) @@ -219,8 +219,8 @@ class GraphicsView(QtGui.QGraphicsView): else: self.fitInView(self.range, QtCore.Qt.IgnoreAspectRatio) - self.sigRangeChanged.emit(self, self.range) - self.sigTransformChanged.emit(self) + self.sigDeviceRangeChanged.emit(self, self.range) + self.sigDeviceTransformChanged.emit(self) if propagate: for v in self.lockedViewports: @@ -287,7 +287,7 @@ class GraphicsView(QtGui.QGraphicsView): image.setPxMode(True) try: self.sigScaleChanged.disconnect(image.setScaledMode) - except TypeError: + except (TypeError, RuntimeError): pass tl = image.sceneBoundingRect().topLeft() w = self.size().width() * pxSize[0] @@ -368,14 +368,14 @@ class GraphicsView(QtGui.QGraphicsView): delta = Point(np.clip(delta[0], -50, 50), np.clip(-delta[1], -50, 50)) scale = 1.01 ** delta self.scale(scale[0], scale[1], center=self.mapToScene(self.mousePressPos)) - self.sigRangeChanged.emit(self, self.range) + self.sigDeviceRangeChanged.emit(self, self.range) elif ev.buttons() in [QtCore.Qt.MidButton, QtCore.Qt.LeftButton]: ## Allow panning by left or mid button. px = self.pixelSize() tr = -delta * px self.translate(tr[0], tr[1]) - self.sigRangeChanged.emit(self, self.range) + self.sigDeviceRangeChanged.emit(self, self.range) def pixelSize(self): """Return vector with the length and width of one view pixel in scene coordinates""" diff --git a/pyqtgraph/widgets/PlotWidget.py b/pyqtgraph/widgets/PlotWidget.py index 12176c7485150d3f1931300642ca6c16f225a53a..e27bce6083ebd923ac02d60ee8966b0e3573454d 100644 --- a/pyqtgraph/widgets/PlotWidget.py +++ b/pyqtgraph/widgets/PlotWidget.py @@ -12,7 +12,9 @@ from ..graphicsItems.PlotItem import * __all__ = ['PlotWidget'] class PlotWidget(GraphicsView): - #sigRangeChanged = QtCore.Signal(object, object) ## already defined in GraphicsView + # signals wrapped from PlotItem / ViewBox + sigRangeChanged = QtCore.Signal(object, object) + sigTransformChanged = QtCore.Signal(object) """ :class:`GraphicsView <pyqtgraph.GraphicsView>` widget with a single