From 42dbd7956a769b37e76a905c324c3b5453e5b7f3 Mon Sep 17 00:00:00 2001 From: Martin Fitzpatrick Date: Fri, 14 Feb 2014 10:29:33 +0100 Subject: [PATCH 1/3] Adding PyQt5 compatibility (broken) Adding compatibility for PyQt5 via a shim in Qt.py. This restructures the PyQt5 libraries to match the layout seen in PyQt4, allowing it to continue to be used as drop in replacement. This works up to the point of importing, however other API changes are broken - for example the deprectation of .scale() on GraphicsItems throws an error currently. --- pyqtgraph/Qt.py | 65 +++++++++++++++---- pyqtgraph/__init__.py | 3 +- .../PlotItem/plotConfigTemplate_pyqt.py | 2 +- .../ViewBox/axisCtrlTemplate_pyqt.py | 2 +- pyqtgraph/imageview/ImageViewTemplate_pyqt.py | 2 +- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/pyqtgraph/Qt.py b/pyqtgraph/Qt.py index 410bfd83..4c15f670 100644 --- a/pyqtgraph/Qt.py +++ b/pyqtgraph/Qt.py @@ -11,25 +11,40 @@ This module exists to smooth out some of the differences between PySide and PyQt import sys, re +PYSIDE = 0 +PYQT4 = 1 +PYQT5 = 2 + +USE_QT_PY = None + ## Automatically determine whether to use PyQt or PySide. ## This is done by first checking to see whether one of the libraries ## is already imported. If not, then attempt to import PyQt4, then PySide. if 'PyQt4' in sys.modules: - USE_PYSIDE = False + USE_QT_PY = PYQT4 +if 'PyQt5' in sys.modules: + USE_QT_PY = PYQT5 elif 'PySide' in sys.modules: - USE_PYSIDE = True + USE_QT_PY = PYSIDE else: try: import PyQt4 - USE_PYSIDE = False + USE_QT_PY = PYQT4 except ImportError: try: - import PySide - USE_PYSIDE = True + import PyQt5 + USE_QT_PY = PYQT5 except ImportError: - raise Exception("PyQtGraph requires either PyQt4 or PySide; neither package could be imported.") + try: + import PySide + USE_QT_PY = PYSIDE + except: + pass -if USE_PYSIDE: +if USE_QT_PY == None: + raise Exception("PyQtGraph requires one of PyQt4, PyQt5 or PySide; none of these packages could be imported.") + +if USE_QT_PY == PYSIDE: from PySide import QtGui, QtCore, QtOpenGL, QtSvg import PySide VERSION_INFO = 'PySide ' + PySide.__version__ @@ -64,9 +79,9 @@ if USE_PYSIDE: base_class = eval('QtGui.%s'%widget_class) return form_class, base_class - - -else: + +elif USE_QT_PY == PYQT4: + from PyQt4 import QtGui, QtCore, uic try: from PyQt4 import QtSvg @@ -83,10 +98,36 @@ else: QtCore.Signal = QtCore.pyqtSignal VERSION_INFO = 'PyQt4 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR - +elif USE_QT_PY == PYQT5: + + # We're using PyQt5 which has a different structure so we're going to use a shim to + # recreate the Qt4 structure for Qt5 + from PyQt5 import QtGui, QtCore, QtWidgets, Qt, uic + try: + from PyQt5 import QtSvg + except ImportError: + pass + try: + from PyQt5 import QtOpenGL + except ImportError: + pass + + QtGui.QApplication = QtWidgets.QApplication + QtGui.QGraphicsScene = QtWidgets.QGraphicsScene + QtGui.QGraphicsObject = QtWidgets.QGraphicsObject + QtGui.QGraphicsWidget = QGraphicsWidget5 + QtGui.QApplication.setGraphicsSystem = None + QtCore.Signal = Qt.pyqtSignal + + # Import all QtWidgets objects into QtGui + for o in dir(QtWidgets): + if o.startswith('Q'): + setattr(QtGui, o, getattr(QtWidgets,o) ) + ## Make sure we have Qt >= 4.7 versionReq = [4, 7] -QtVersion = PySide.QtCore.__version__ if USE_PYSIDE else QtCore.QT_VERSION_STR +USE_PYSIDE = USE_QT_PY == PYSIDE # still needed internally elsewhere +QtVersion = PySide.QtCore.__version__ if USE_QT_PY == PYSIDE else QtCore.QT_VERSION_STR m = re.match(r'(\d+)\.(\d+).*', QtVersion) if m is not None and list(map(int, m.groups())) < versionReq: print(list(map(int, m.groups()))) diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index 588de0cd..f8951af7 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -41,7 +41,8 @@ elif 'darwin' in sys.platform: ## openGL can have a major impact on mac, but als useOpenGL = False if QtGui.QApplication.instance() is not None: print('Warning: QApplication was created before pyqtgraph was imported; there may be problems (to avoid bugs, call QApplication.setGraphicsSystem("raster") before the QApplication is created).') - QtGui.QApplication.setGraphicsSystem('raster') ## work around a variety of bugs in the native graphics system + if QtGui.QApplication.setGraphicsSystem: + QtGui.QApplication.setGraphicsSystem('raster') ## work around a variety of bugs in the native graphics system else: useOpenGL = False ## on windows there's a more even performance / bugginess tradeoff. diff --git a/pyqtgraph/graphicsItems/PlotItem/plotConfigTemplate_pyqt.py b/pyqtgraph/graphicsItems/PlotItem/plotConfigTemplate_pyqt.py index e09c9978..a06519bf 100644 --- a/pyqtgraph/graphicsItems/PlotItem/plotConfigTemplate_pyqt.py +++ b/pyqtgraph/graphicsItems/PlotItem/plotConfigTemplate_pyqt.py @@ -7,7 +7,7 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore, QtGui +from ...Qt import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 diff --git a/pyqtgraph/graphicsItems/ViewBox/axisCtrlTemplate_pyqt.py b/pyqtgraph/graphicsItems/ViewBox/axisCtrlTemplate_pyqt.py index d8ef1925..5d952741 100644 --- a/pyqtgraph/graphicsItems/ViewBox/axisCtrlTemplate_pyqt.py +++ b/pyqtgraph/graphicsItems/ViewBox/axisCtrlTemplate_pyqt.py @@ -7,7 +7,7 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore, QtGui +from ...Qt import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 diff --git a/pyqtgraph/imageview/ImageViewTemplate_pyqt.py b/pyqtgraph/imageview/ImageViewTemplate_pyqt.py index 78156317..18b68e96 100644 --- a/pyqtgraph/imageview/ImageViewTemplate_pyqt.py +++ b/pyqtgraph/imageview/ImageViewTemplate_pyqt.py @@ -7,7 +7,7 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore, QtGui +from ..Qt import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 From b244805bde2775742952562069749361479e257e Mon Sep 17 00:00:00 2001 From: Martin Fitzpatrick Date: Fri, 14 Feb 2014 10:57:05 +0100 Subject: [PATCH 2/3] Basic plot function works. --- pyqtgraph/Qt.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pyqtgraph/Qt.py b/pyqtgraph/Qt.py index 4c15f670..5d137fb8 100644 --- a/pyqtgraph/Qt.py +++ b/pyqtgraph/Qt.py @@ -111,11 +111,26 @@ elif USE_QT_PY == PYQT5: from PyQt5 import QtOpenGL except ImportError: pass + + # Re-implement deprecated APIs + def scale(self, sx, sy): + self.setTransform(QtGui.QTransform.fromScale(sx, sy), True) + QtWidgets.QGraphicsItem.scale = scale + + def rotate(self, angle): + self.setRotation(self.rotation() + angle) + QtWidgets.QGraphicsItem.rotate = rotate + + + def setMargin(self, i): + self.setContentsMargins( i, i, i, i) + QtWidgets.QGridLayout.setMargin = setMargin QtGui.QApplication = QtWidgets.QApplication QtGui.QGraphicsScene = QtWidgets.QGraphicsScene QtGui.QGraphicsObject = QtWidgets.QGraphicsObject - QtGui.QGraphicsWidget = QGraphicsWidget5 + QtGui.QGraphicsWidget = QtWidgets.QGraphicsWidget + QtGui.QApplication.setGraphicsSystem = None QtCore.Signal = Qt.pyqtSignal From e0c22e27965bd6b44d7e07a175561d0b4b8ef164 Mon Sep 17 00:00:00 2001 From: Martin Fitzpatrick Date: Fri, 14 Feb 2014 11:05:10 +0100 Subject: [PATCH 3/3] Adding some additional deprectated APIs for Qt5. Example plots (mostly) working. This adds some remaining APIs that were deprecated in Qt5. These are easy to do as they're all documented, e.g. http://qt-project.org/doc/qt-5.0/qtwidgets/qgraphicsitem-compat.html Tested with most of the examples. Although I can't be sure as I don't know what the 'correct' output is, they look like they work. Some issues with interaction e.g. on the color bar plot. --- pyqtgraph/Qt.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pyqtgraph/Qt.py b/pyqtgraph/Qt.py index 5d137fb8..b7a479b7 100644 --- a/pyqtgraph/Qt.py +++ b/pyqtgraph/Qt.py @@ -121,10 +121,18 @@ elif USE_QT_PY == PYQT5: self.setRotation(self.rotation() + angle) QtWidgets.QGraphicsItem.rotate = rotate + def translate(self, dx, dy): + self.setTransform(QtGui.QTransform.fromTranslate(dx, dy), True) + QtWidgets.QGraphicsItem.translate = translate def setMargin(self, i): - self.setContentsMargins( i, i, i, i) + self.setContentsMargins(i, i, i, i) QtWidgets.QGridLayout.setMargin = setMargin + + def setResizeMode(self, mode): + self.setSectionResizeMode(mode) + QtWidgets.QHeaderView.setResizeMode = setResizeMode + QtGui.QApplication = QtWidgets.QApplication QtGui.QGraphicsScene = QtWidgets.QGraphicsScene