Fixed PySide issues by removing itemChange methods from GraphicsWidget and ViewBox;

Workaround is for ViewBox to see whether its scene has changed every time it paints.

Fixes: 12
This commit is contained in:
Luke Campagnola 2013-11-16 20:23:41 -05:00
parent 25d666a1da
commit 8d7ab108fd
6 changed files with 89 additions and 54 deletions

View File

@ -13,7 +13,6 @@ import initExample ## Add path to library (just for examples; you do not need th
from pyqtgraph.Qt import QtGui, QtCore, USE_PYSIDE from pyqtgraph.Qt import QtGui, QtCore, USE_PYSIDE
import numpy as np import numpy as np
import pyqtgraph as pg import pyqtgraph as pg
from pyqtgraph import RawImageWidget
import scipy.ndimage as ndi import scipy.ndimage as ndi
import pyqtgraph.ptime as ptime import pyqtgraph.ptime as ptime

View File

@ -22,9 +22,6 @@
<property name="text"> <property name="text">
<string>RawImageWidget</string> <string>RawImageWidget</string>
</property> </property>
<property name="checked">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
@ -32,6 +29,9 @@
<property name="text"> <property name="text">
<string>GraphicsView + ImageItem</string> <string>GraphicsView + ImageItem</string>
</property> </property>
<property name="checked">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
@ -265,7 +265,7 @@
<customwidget> <customwidget>
<class>RawImageWidget</class> <class>RawImageWidget</class>
<extends>QWidget</extends> <extends>QWidget</extends>
<header>pyqtgraph</header> <header>pyqtgraph.widgets.RawImageWidget</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget> <customwidget>

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file './VideoTemplate.ui' # Form implementation generated from reading ui file './VideoTemplate.ui'
# #
# Created: Tue Jul 9 23:38:17 2013 # Created: Sat Nov 16 20:07:09 2013
# by: PyQt4 UI code generator 4.9.3 # by: PyQt4 UI code generator 4.10
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -12,7 +12,16 @@ from PyQt4 import QtCore, QtGui
try: try:
_fromUtf8 = QtCore.QString.fromUtf8 _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError: except AttributeError:
_fromUtf8 = lambda s: s def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, MainWindow): def setupUi(self, MainWindow):
@ -25,10 +34,10 @@ class Ui_MainWindow(object):
self.gridLayout = QtGui.QGridLayout() self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.rawRadio = QtGui.QRadioButton(self.centralwidget) self.rawRadio = QtGui.QRadioButton(self.centralwidget)
self.rawRadio.setChecked(True)
self.rawRadio.setObjectName(_fromUtf8("rawRadio")) self.rawRadio.setObjectName(_fromUtf8("rawRadio"))
self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1) self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1)
self.gfxRadio = QtGui.QRadioButton(self.centralwidget) self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
self.gfxRadio.setChecked(True)
self.gfxRadio.setObjectName(_fromUtf8("gfxRadio")) self.gfxRadio.setObjectName(_fromUtf8("gfxRadio"))
self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1) self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1)
self.stack = QtGui.QStackedWidget(self.centralwidget) self.stack = QtGui.QStackedWidget(self.centralwidget)
@ -158,23 +167,23 @@ class Ui_MainWindow(object):
QtCore.QMetaObject.connectSlotsByName(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow): def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget", None, QtGui.QApplication.UnicodeUTF8)) self.rawRadio.setText(_translate("MainWindow", "RawImageWidget", None))
self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem", None, QtGui.QApplication.UnicodeUTF8)) self.gfxRadio.setText(_translate("MainWindow", "GraphicsView + ImageItem", None))
self.rawGLRadio.setText(QtGui.QApplication.translate("MainWindow", "RawGLImageWidget", None, QtGui.QApplication.UnicodeUTF8)) self.rawGLRadio.setText(_translate("MainWindow", "RawGLImageWidget", None))
self.label.setText(QtGui.QApplication.translate("MainWindow", "Data type", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(_translate("MainWindow", "Data type", None))
self.dtypeCombo.setItemText(0, QtGui.QApplication.translate("MainWindow", "uint8", None, QtGui.QApplication.UnicodeUTF8)) self.dtypeCombo.setItemText(0, _translate("MainWindow", "uint8", None))
self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8)) self.dtypeCombo.setItemText(1, _translate("MainWindow", "uint16", None))
self.dtypeCombo.setItemText(2, QtGui.QApplication.translate("MainWindow", "float", None, QtGui.QApplication.UnicodeUTF8)) self.dtypeCombo.setItemText(2, _translate("MainWindow", "float", None))
self.scaleCheck.setText(QtGui.QApplication.translate("MainWindow", "Scale Data", None, QtGui.QApplication.UnicodeUTF8)) self.scaleCheck.setText(_translate("MainWindow", "Scale Data", None))
self.rgbLevelsCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8)) self.rgbLevelsCheck.setText(_translate("MainWindow", "RGB", None))
self.label_2.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8)) self.label_2.setText(_translate("MainWindow", "<--->", None))
self.label_3.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8)) self.label_3.setText(_translate("MainWindow", "<--->", None))
self.label_4.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8)) self.label_4.setText(_translate("MainWindow", "<--->", None))
self.lutCheck.setText(QtGui.QApplication.translate("MainWindow", "Use Lookup Table", None, QtGui.QApplication.UnicodeUTF8)) self.lutCheck.setText(_translate("MainWindow", "Use Lookup Table", None))
self.alphaCheck.setText(QtGui.QApplication.translate("MainWindow", "alpha", None, QtGui.QApplication.UnicodeUTF8)) self.alphaCheck.setText(_translate("MainWindow", "alpha", None))
self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8)) self.fpsLabel.setText(_translate("MainWindow", "FPS", None))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8)) self.rgbCheck.setText(_translate("MainWindow", "RGB", None))
from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget, RawImageWidget
from pyqtgraph import GradientWidget, SpinBox, GraphicsView, RawImageWidget from pyqtgraph import GradientWidget, SpinBox, GraphicsView

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file './VideoTemplate.ui' # Form implementation generated from reading ui file './VideoTemplate.ui'
# #
# Created: Tue Jul 9 23:38:19 2013 # Created: Sat Nov 16 20:07:10 2013
# by: pyside-uic 0.2.13 running on PySide 1.1.2 # by: pyside-uic 0.2.14 running on PySide 1.1.2
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -20,10 +20,10 @@ class Ui_MainWindow(object):
self.gridLayout = QtGui.QGridLayout() self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.rawRadio = QtGui.QRadioButton(self.centralwidget) self.rawRadio = QtGui.QRadioButton(self.centralwidget)
self.rawRadio.setChecked(True)
self.rawRadio.setObjectName("rawRadio") self.rawRadio.setObjectName("rawRadio")
self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1) self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1)
self.gfxRadio = QtGui.QRadioButton(self.centralwidget) self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
self.gfxRadio.setChecked(True)
self.gfxRadio.setObjectName("gfxRadio") self.gfxRadio.setObjectName("gfxRadio")
self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1) self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1)
self.stack = QtGui.QStackedWidget(self.centralwidget) self.stack = QtGui.QStackedWidget(self.centralwidget)
@ -171,5 +171,5 @@ class Ui_MainWindow(object):
self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8)) self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8)) self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget, RawImageWidget
from pyqtgraph import GradientWidget, SpinBox, GraphicsView, RawImageWidget from pyqtgraph import GradientWidget, SpinBox, GraphicsView

View File

@ -20,15 +20,16 @@ class GraphicsWidget(GraphicsItem, QtGui.QGraphicsWidget):
## done by GraphicsItem init ## done by GraphicsItem init
#GraphicsScene.registerObject(self) ## workaround for pyqt bug in graphicsscene.items() #GraphicsScene.registerObject(self) ## workaround for pyqt bug in graphicsscene.items()
## Removed because this causes segmentation faults. Don't know why. # Removed due to https://bugreports.qt-project.org/browse/PYSIDE-86
# def itemChange(self, change, value): #def itemChange(self, change, value):
# ret = QtGui.QGraphicsWidget.itemChange(self, change, value) ## segv occurs here ## BEWARE: Calling QGraphicsWidget.itemChange can lead to crashing!
# if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]: ##ret = QtGui.QGraphicsWidget.itemChange(self, change, value) ## segv occurs here
# self._updateView() ## The default behavior is just to return the value argument, so we'll do that
# return ret ## without calling the original method.
#ret = value
#def getMenu(self): #if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]:
#pass #self._updateView()
#return ret
def setFixedHeight(self, h): def setFixedHeight(self, h):
self.setMaximumHeight(h) self.setMaximumHeight(h)

View File

@ -94,6 +94,8 @@ class ViewBox(GraphicsWidget):
self._matrixNeedsUpdate = True ## indicates that range has changed, but matrix update was deferred self._matrixNeedsUpdate = True ## indicates that range has changed, but matrix update was deferred
self._autoRangeNeedsUpdate = True ## indicates auto-range needs to be recomputed. self._autoRangeNeedsUpdate = True ## indicates auto-range needs to be recomputed.
self._lastScene = None ## stores reference to the last known scene this view was a part of.
self.state = { self.state = {
## separating targetRange and viewRange allows the view to be resized ## separating targetRange and viewRange allows the view to be resized
@ -200,18 +202,40 @@ class ViewBox(GraphicsWidget):
def implements(self, interface): def implements(self, interface):
return interface == 'ViewBox' return interface == 'ViewBox'
def itemChange(self, change, value): # removed due to https://bugreports.qt-project.org/browse/PYSIDE-86
# Note: Calling QWidget.itemChange causes segv in python 3 + PyQt #def itemChange(self, change, value):
ret = QtGui.QGraphicsItem.itemChange(self, change, value) ## Note: Calling QWidget.itemChange causes segv in python 3 + PyQt
if change == self.ItemSceneChange: ##ret = QtGui.QGraphicsItem.itemChange(self, change, value)
scene = self.scene() #ret = GraphicsWidget.itemChange(self, change, value)
if scene is not None: #if change == self.ItemSceneChange:
scene.sigPrepareForPaint.disconnect(self.prepareForPaint) #scene = self.scene()
elif change == self.ItemSceneHasChanged: #if scene is not None and hasattr(scene, 'sigPrepareForPaint'):
scene = self.scene() #scene.sigPrepareForPaint.disconnect(self.prepareForPaint)
if scene is not None: #elif change == self.ItemSceneHasChanged:
scene.sigPrepareForPaint.connect(self.prepareForPaint) #scene = self.scene()
return ret #if scene is not None and hasattr(scene, 'sigPrepareForPaint'):
#scene.sigPrepareForPaint.connect(self.prepareForPaint)
#return ret
def checkSceneChange(self):
# ViewBox needs to receive sigPrepareForPaint from its scene before
# being painted. However, we have no way of being informed when the
# scene has changed in order to make this connection. The usual way
# to do this is via itemChange(), but bugs prevent this approach
# (see above). Instead, we simply check at every paint to see whether
# (the scene has changed.
scene = self.scene()
if scene == self._lastScene:
return
if self._lastScene is not None and hasattr(self.lastScene, 'sigPrepareForPaint'):
self._lastScene.sigPrepareForPaint.disconnect(self.prepareForPaint)
if scene is not None and hasattr(scene, 'sigPrepareForPaint'):
scene.sigPrepareForPaint.connect(self.prepareForPaint)
self.prepareForPaint()
self._lastScene = scene
def prepareForPaint(self): def prepareForPaint(self):
#autoRangeEnabled = (self.state['autoRange'][0] is not False) or (self.state['autoRange'][1] is not False) #autoRangeEnabled = (self.state['autoRange'][0] is not False) or (self.state['autoRange'][1] is not False)
@ -1446,6 +1470,8 @@ class ViewBox(GraphicsWidget):
self._matrixNeedsUpdate = False self._matrixNeedsUpdate = False
def paint(self, p, opt, widget): def paint(self, p, opt, widget):
self.checkSceneChange()
if self.border is not None: if self.border is not None:
bounds = self.shape() bounds = self.shape()
p.setPen(self.border) p.setPen(self.border)