diff --git a/pyqtgraph/Qt/QtCore/__init__.py b/pyqtgraph/Qt/QtCore/__init__.py index e69de29bb2..0de152521d 100644 --- a/pyqtgraph/Qt/QtCore/__init__.py +++ b/pyqtgraph/Qt/QtCore/__init__.py @@ -0,0 +1,8 @@ +import importlib +from .. import QT_LIB +module = importlib.import_module(f'{QT_LIB}.QtCore') + +def __getattr__(name): + x = getattr(module, name) + globals()[name] = x + return x diff --git a/pyqtgraph/Qt/QtGui/__init__.py b/pyqtgraph/Qt/QtGui/__init__.py index e69de29bb2..7736c54198 100644 --- a/pyqtgraph/Qt/QtGui/__init__.py +++ b/pyqtgraph/Qt/QtGui/__init__.py @@ -0,0 +1,8 @@ +import importlib +from .. import QT_LIB +module = importlib.import_module(f'{QT_LIB}.QtGui') + +def __getattr__(name): + x = getattr(module, name) + globals()[name] = x + return x diff --git a/pyqtgraph/Qt/QtWidgets/__init__.py b/pyqtgraph/Qt/QtWidgets/__init__.py index e69de29bb2..f01c003867 100644 --- a/pyqtgraph/Qt/QtWidgets/__init__.py +++ b/pyqtgraph/Qt/QtWidgets/__init__.py @@ -0,0 +1,8 @@ +import importlib +from .. import QT_LIB +module = importlib.import_module(f'{QT_LIB}.QtWidgets') + +def __getattr__(name): + x = getattr(module, name) + globals()[name] = x + return x diff --git a/pyqtgraph/Qt/__init__.py b/pyqtgraph/Qt/__init__.py index 2356f1a4f6..124cbc233c 100644 --- a/pyqtgraph/Qt/__init__.py +++ b/pyqtgraph/Qt/__init__.py @@ -110,23 +110,10 @@ def _loadUiType(uiFile): # To avoid this, we now maintain a local "mirror" of QtCore, QtGui and QtWidgets. # Thus, when monkey-patching happens later on in this file, they will only affect # the local modules and not the global modules. -def _copy_attrs(src, dst): - for o in dir(src): - if not hasattr(dst, o): - setattr(dst, o, getattr(src, o)) from . import QtCore, QtGui, QtWidgets, compat if QT_LIB == 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 - import PyQt5.QtCore - import PyQt5.QtGui - import PyQt5.QtWidgets - _copy_attrs(PyQt5.QtCore, QtCore) - _copy_attrs(PyQt5.QtGui, QtGui) - _copy_attrs(PyQt5.QtWidgets, QtWidgets) - try: from PyQt5 import sip except ImportError: @@ -146,23 +133,12 @@ def _copy_attrs(src, dst): VERSION_INFO = 'PyQt5 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR elif QT_LIB == PYQT6: - import PyQt6.QtCore - import PyQt6.QtGui - import PyQt6.QtWidgets - _copy_attrs(PyQt6.QtCore, QtCore) - _copy_attrs(PyQt6.QtGui, QtGui) - _copy_attrs(PyQt6.QtWidgets, QtWidgets) - from PyQt6 import sip, uic try: from PyQt6 import QtSvg except ImportError as err: QtSvg = FailedImport(err) - try: - from PyQt6 import QtOpenGLWidgets - except ImportError as err: - QtOpenGLWidgets = FailedImport(err) try: from PyQt6 import QtTest except ImportError as err: @@ -171,13 +147,6 @@ def _copy_attrs(src, dst): VERSION_INFO = 'PyQt6 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR elif QT_LIB == PYSIDE2: - import PySide2.QtCore - import PySide2.QtGui - import PySide2.QtWidgets - _copy_attrs(PySide2.QtCore, QtCore) - _copy_attrs(PySide2.QtGui, QtGui) - _copy_attrs(PySide2.QtWidgets, QtWidgets) - try: from PySide2 import QtSvg except ImportError as err: @@ -191,21 +160,10 @@ def _copy_attrs(src, dst): import shiboken2 as shiboken VERSION_INFO = 'PySide2 ' + PySide2.__version__ + ' Qt ' + QtCore.__version__ elif QT_LIB == PYSIDE6: - import PySide6.QtCore - import PySide6.QtGui - import PySide6.QtWidgets - _copy_attrs(PySide6.QtCore, QtCore) - _copy_attrs(PySide6.QtGui, QtGui) - _copy_attrs(PySide6.QtWidgets, QtWidgets) - try: from PySide6 import QtSvg except ImportError as err: QtSvg = FailedImport(err) - try: - from PySide6 import QtOpenGLWidgets - except ImportError as err: - QtOpenGLWidgets = FailedImport(err) try: from PySide6 import QtTest except ImportError as err: @@ -221,12 +179,6 @@ def _copy_attrs(src, dst): if QT_LIB in [PYQT6, PYSIDE6]: - # We're using Qt6 which has a different structure so we're going to use a shim to - # recreate the Qt5 structure - - if not isinstance(QtOpenGLWidgets, FailedImport): - QtWidgets.QOpenGLWidget = QtOpenGLWidgets.QOpenGLWidget - # PySide6 incorrectly placed QFileSystemModel inside QtWidgets if QT_LIB == PYSIDE6 and hasattr(QtWidgets, 'QFileSystemModel'): module = getattr(QtWidgets, "QFileSystemModel") diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index 19a4403866..8f7aacb180 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -419,24 +419,25 @@ def correctCoordinates(node, defs, item, options): ch.setAttribute('points', ' '.join([','.join([str(a) for a in c]) for c in coords])) elif ch.tagName == 'path': removeTransform = True - newCoords = '' oldCoords = ch.getAttribute('d').strip() if oldCoords == '': continue + newCoords = [] for c in oldCoords.split(' '): - c = c.strip() - if c == 'Z' or c == 'z': - # Preserve the Z command as-is - newCoords += c + ' ' - continue - x,y = c.split(',') - if x[0].isalpha(): - t = x[0] - x = x[1:] + tokens = c.split(',') + if len(tokens) == 1: + # this might be a Z + newCoords.append(tokens[0]) else: - t = '' - nc = fn.transformCoordinates(tr, np.array([[float(x),float(y)]]), transpose=True) - newCoords += t+str(nc[0,0])+','+str(nc[0,1])+' ' + x, y = tokens + if x[0].isalpha(): + t = x[0] + x = x[1:] + else: + t = '' + nc = fn.transformCoordinates(tr, np.array([[float(x),float(y)]]), transpose=True) + newCoords.append(t+str(nc[0,0])+','+str(nc[0,1])) + newCoords = ' '.join(newCoords) # If coords start with L instead of M, then the entire path will not be rendered. # (This can happen if the first point had nan values in it--Qt will skip it on export) if newCoords[0] != 'M': diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py index 1b687aa933..223449e68b 100644 --- a/pyqtgraph/graphicsItems/PlotCurveItem.py +++ b/pyqtgraph/graphicsItems/PlotCurveItem.py @@ -15,8 +15,10 @@ if QtVersionInfo[0] >= 6: QtOpenGL = importlib.import_module(f"{QT_LIB}.QtOpenGL") + QtOpenGLWidgets = importlib.import_module(f"{QT_LIB}.QtOpenGLWidgets") else: QtOpenGL = QtGui + QtOpenGLWidgets = QtWidgets __all__ = ['PlotCurveItem'] @@ -875,7 +877,7 @@ def _getFillPathList(self, widget): # Note: when OpenGL mode is enabled, we should normally be using the # 'paintGL' method, and should not even reach here. # Values were found using 'PlotSpeedTest.py' example, see #2257. - chunksize = 50 if not isinstance(widget, QtWidgets.QOpenGLWidget) else 5000 + chunksize = 50 if not isinstance(widget, QtOpenGLWidgets.QOpenGLWidget) else 5000 connect_kind = self.opts['connect'] if isinstance(connect_kind, np.ndarray): diff --git a/pyqtgraph/opengl/GLViewWidget.py b/pyqtgraph/opengl/GLViewWidget.py index b23a3e57d6..4b9314c557 100644 --- a/pyqtgraph/opengl/GLViewWidget.py +++ b/pyqtgraph/opengl/GLViewWidget.py @@ -12,8 +12,10 @@ if QtVersionInfo[0] >= 6: QtOpenGL = importlib.import_module(f"{QT_LIB}.QtOpenGL") + QtOpenGLWidgets = importlib.import_module(f"{QT_LIB}.QtOpenGLWidgets") else: QtOpenGL = QtGui + QtOpenGLWidgets = QtWidgets class GLViewMixin: def __init__(self, *args, rotationMethod='euler', **kwargs): @@ -211,6 +213,10 @@ def itemsAt(self, region=None): return [self._itemNames[i[1]] for i in items] def paintGL(self): + # Qt may have triggered some OpenGL errors, drain those errors away. + while GL.glGetError() != GL.GL_NO_ERROR: + pass + # when called by Qt, glViewport has already been called # with device pixel ratio taken of region = self.getViewport() @@ -547,7 +553,7 @@ def renderToArray(self, size, format=GL.GL_BGRA, type=GL.GL_UNSIGNED_BYTE, textu return output -class GLViewWidget(GLViewMixin, QtWidgets.QOpenGLWidget): +class GLViewWidget(GLViewMixin, QtOpenGLWidgets.QOpenGLWidget): def __init__(self, *args, devicePixelRatio=None, **kwargs): """ Basic widget for displaying 3D data