diff --git a/CHANGELOG b/CHANGELOG index 81e384ee..ec558564 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 27586040..48357b30 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 3cf33acd..d2ee393c 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 8d2238b8..e34086bd 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 9d0c3240..632e7cdf 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 6e7d6305..1aa3f3f4 100644 --- a/pyqtgraph/graphicsWindows.py +++ b/pyqtgraph/graphicsWindows.py @@ -19,11 +19,14 @@ def mkQApp(): class GraphicsWindow(GraphicsLayoutWidget): + """ + Convenience subclass of :class:`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 c62432f2..f7cb42a0 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 3c34ca58..ec7b9e0d 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 + ` with a single :class:`GraphicsLayout + ` as its central item. + + This class wraps several methods from its internal GraphicsLayout: + :func:`nextRow ` + :func:`nextColumn ` + :func:`addPlot ` + :func:`addViewBox ` + :func:`addItem ` + :func:`getItem ` + :func:`addLabel ` + :func:`addLayout ` + :func:`removeItem ` + :func:`itemIndex ` + :func:`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 70472fd3..649a5ec8 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 12176c74..e27bce60 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 ` widget with a single