Merge pull request #1502 from pijyoi/pyqt6_compat

Pyqt6 compat
This commit is contained in:
Ogi Moore 2021-01-22 17:42:36 -08:00 committed by GitHub
commit 8670407779
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 1665 additions and 366 deletions

View File

@ -31,7 +31,7 @@ jobs:
numpy-version: "~=1.19.0" numpy-version: "~=1.19.0"
- python-version: "3.9" - python-version: "3.9"
qt-lib: "pyqt" qt-lib: "pyqt"
qt-version: "PyQt5~=5.15" qt-version: "PyQt6"
numpy-version: "~=1.19.0" numpy-version: "~=1.19.0"
- python-version: "3.9" - python-version: "3.9"
qt-lib: "pyside" qt-lib: "pyside"

View File

@ -9,7 +9,7 @@ PyQtGraph
[![Total alerts](https://img.shields.io/lgtm/alerts/g/pyqtgraph/pyqtgraph.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/pyqtgraph/pyqtgraph/alerts/) [![Total alerts](https://img.shields.io/lgtm/alerts/g/pyqtgraph/pyqtgraph.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/pyqtgraph/pyqtgraph/alerts/)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/pyqtgraph/pyqtgraph.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/pyqtgraph/pyqtgraph/context:python) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/pyqtgraph/pyqtgraph.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/pyqtgraph/pyqtgraph/context:python)
A pure-Python graphics library for PyQt5/PySide2/PySide6 A pure-Python graphics library for PyQt5/PyQt6/PySide2/PySide6
Copyright 2020 Luke Campagnola, University of North Carolina at Chapel Hill Copyright 2020 Luke Campagnola, University of North Carolina at Chapel Hill
@ -36,7 +36,7 @@ Currently this means:
* Python 3.7+ * Python 3.7+
* Qt 5.12-6.0 * Qt 5.12-6.0
* Required * Required
* PyQt5, PySide2 or PySide6 * PyQt5, PyQt6, PySide2 or PySide6
* `numpy` 1.17+ * `numpy` 1.17+
* Optional * Optional
* `scipy` for image processing * `scipy` for image processing
@ -57,8 +57,9 @@ The following table represents the python environments we test in our CI system.
| PySide2-5.12 | :white_check_mark: | :x: | :x: | | PySide2-5.12 | :white_check_mark: | :x: | :x: |
| PyQt5-5.12 | :white_check_mark: | :x: | :x: | | PyQt5-5.12 | :white_check_mark: | :x: | :x: |
| PySide2-5.15 | :x: | :white_check_mark: | :x: | | PySide2-5.15 | :x: | :white_check_mark: | :x: |
| PyQt5-5.15 | :x: | :white_check_mark: | :white_check_mark: | | PyQt5-5.15 | :x: | :white_check_mark: | :x: |
| PySide6-6.0 | :x: | :x: | :white_check_mark: | | PySide6-6.0 | :x: | :x: | :white_check_mark: |
| PyQt6-6.0 | :x: | :x: | :white_check_mark: |
Support Support
------- -------

View File

@ -0,0 +1,44 @@
# Form implementation generated from reading ui file 'examples\ScatterPlotSpeedTestTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setObjectName("gridLayout")
self.sizeSpin = QtWidgets.QSpinBox(Form)
self.sizeSpin.setProperty("value", 10)
self.sizeSpin.setObjectName("sizeSpin")
self.gridLayout.addWidget(self.sizeSpin, 1, 1, 1, 1)
self.pixelModeCheck = QtWidgets.QCheckBox(Form)
self.pixelModeCheck.setObjectName("pixelModeCheck")
self.gridLayout.addWidget(self.pixelModeCheck, 1, 3, 1, 1)
self.label = QtWidgets.QLabel(Form)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
self.plot = PlotWidget(Form)
self.plot.setObjectName("plot")
self.gridLayout.addWidget(self.plot, 0, 0, 1, 4)
self.randCheck = QtWidgets.QCheckBox(Form)
self.randCheck.setObjectName("randCheck")
self.gridLayout.addWidget(self.randCheck, 1, 2, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.pixelModeCheck.setText(_translate("Form", "pixel mode"))
self.label.setText(_translate("Form", "Size"))
self.randCheck.setText(_translate("Form", "Randomize"))
from pyqtgraph import PlotWidget

View File

@ -0,0 +1,203 @@
# Form implementation generated from reading ui file 'VideoTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(695, 798)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.cudaCheck = QtWidgets.QCheckBox(self.centralwidget)
self.cudaCheck.setObjectName("cudaCheck")
self.gridLayout_2.addWidget(self.cudaCheck, 9, 0, 1, 2)
self.downsampleCheck = QtWidgets.QCheckBox(self.centralwidget)
self.downsampleCheck.setObjectName("downsampleCheck")
self.gridLayout_2.addWidget(self.downsampleCheck, 8, 0, 1, 2)
self.scaleCheck = QtWidgets.QCheckBox(self.centralwidget)
self.scaleCheck.setObjectName("scaleCheck")
self.gridLayout_2.addWidget(self.scaleCheck, 4, 0, 1, 1)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.rawRadio = QtWidgets.QRadioButton(self.centralwidget)
self.rawRadio.setObjectName("rawRadio")
self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1)
self.gfxRadio = QtWidgets.QRadioButton(self.centralwidget)
self.gfxRadio.setChecked(True)
self.gfxRadio.setObjectName("gfxRadio")
self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1)
self.stack = QtWidgets.QStackedWidget(self.centralwidget)
self.stack.setObjectName("stack")
self.page = QtWidgets.QWidget()
self.page.setObjectName("page")
self.gridLayout_3 = QtWidgets.QGridLayout(self.page)
self.gridLayout_3.setObjectName("gridLayout_3")
self.graphicsView = GraphicsView(self.page)
self.graphicsView.setObjectName("graphicsView")
self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 1)
self.stack.addWidget(self.page)
self.page_2 = QtWidgets.QWidget()
self.page_2.setObjectName("page_2")
self.gridLayout_4 = QtWidgets.QGridLayout(self.page_2)
self.gridLayout_4.setObjectName("gridLayout_4")
self.rawImg = RawImageWidget(self.page_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.rawImg.sizePolicy().hasHeightForWidth())
self.rawImg.setSizePolicy(sizePolicy)
self.rawImg.setObjectName("rawImg")
self.gridLayout_4.addWidget(self.rawImg, 0, 0, 1, 1)
self.stack.addWidget(self.page_2)
self.gridLayout.addWidget(self.stack, 0, 0, 1, 1)
self.rawGLRadio = QtWidgets.QRadioButton(self.centralwidget)
self.rawGLRadio.setObjectName("rawGLRadio")
self.gridLayout.addWidget(self.rawGLRadio, 4, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 4)
self.dtypeCombo = QtWidgets.QComboBox(self.centralwidget)
self.dtypeCombo.setObjectName("dtypeCombo")
self.dtypeCombo.addItem("")
self.dtypeCombo.addItem("")
self.dtypeCombo.addItem("")
self.gridLayout_2.addWidget(self.dtypeCombo, 3, 2, 1, 1)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 3, 0, 1, 1)
self.rgbLevelsCheck = QtWidgets.QCheckBox(self.centralwidget)
self.rgbLevelsCheck.setObjectName("rgbLevelsCheck")
self.gridLayout_2.addWidget(self.rgbLevelsCheck, 4, 1, 1, 1)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.minSpin2 = SpinBox(self.centralwidget)
self.minSpin2.setEnabled(False)
self.minSpin2.setObjectName("minSpin2")
self.horizontalLayout_2.addWidget(self.minSpin2)
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setAlignment(QtCore.Qt.Alignment.AlignCenter)
self.label_3.setObjectName("label_3")
self.horizontalLayout_2.addWidget(self.label_3)
self.maxSpin2 = SpinBox(self.centralwidget)
self.maxSpin2.setEnabled(False)
self.maxSpin2.setObjectName("maxSpin2")
self.horizontalLayout_2.addWidget(self.maxSpin2)
self.gridLayout_2.addLayout(self.horizontalLayout_2, 5, 2, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.minSpin1 = SpinBox(self.centralwidget)
self.minSpin1.setObjectName("minSpin1")
self.horizontalLayout.addWidget(self.minSpin1)
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setAlignment(QtCore.Qt.Alignment.AlignCenter)
self.label_2.setObjectName("label_2")
self.horizontalLayout.addWidget(self.label_2)
self.maxSpin1 = SpinBox(self.centralwidget)
self.maxSpin1.setObjectName("maxSpin1")
self.horizontalLayout.addWidget(self.maxSpin1)
self.gridLayout_2.addLayout(self.horizontalLayout, 4, 2, 1, 1)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.minSpin3 = SpinBox(self.centralwidget)
self.minSpin3.setEnabled(False)
self.minSpin3.setObjectName("minSpin3")
self.horizontalLayout_3.addWidget(self.minSpin3)
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setAlignment(QtCore.Qt.Alignment.AlignCenter)
self.label_4.setObjectName("label_4")
self.horizontalLayout_3.addWidget(self.label_4)
self.maxSpin3 = SpinBox(self.centralwidget)
self.maxSpin3.setEnabled(False)
self.maxSpin3.setObjectName("maxSpin3")
self.horizontalLayout_3.addWidget(self.maxSpin3)
self.gridLayout_2.addLayout(self.horizontalLayout_3, 6, 2, 1, 1)
self.lutCheck = QtWidgets.QCheckBox(self.centralwidget)
self.lutCheck.setObjectName("lutCheck")
self.gridLayout_2.addWidget(self.lutCheck, 7, 0, 1, 1)
self.alphaCheck = QtWidgets.QCheckBox(self.centralwidget)
self.alphaCheck.setObjectName("alphaCheck")
self.gridLayout_2.addWidget(self.alphaCheck, 7, 1, 1, 1)
self.gradient = GradientWidget(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.gradient.sizePolicy().hasHeightForWidth())
self.gradient.setSizePolicy(sizePolicy)
self.gradient.setObjectName("gradient")
self.gridLayout_2.addWidget(self.gradient, 7, 2, 1, 2)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.gridLayout_2.addItem(spacerItem, 3, 3, 1, 1)
self.fpsLabel = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setPointSize(12)
self.fpsLabel.setFont(font)
self.fpsLabel.setAlignment(QtCore.Qt.Alignment.AlignCenter)
self.fpsLabel.setObjectName("fpsLabel")
self.gridLayout_2.addWidget(self.fpsLabel, 0, 0, 1, 4)
self.rgbCheck = QtWidgets.QCheckBox(self.centralwidget)
self.rgbCheck.setObjectName("rgbCheck")
self.gridLayout_2.addWidget(self.rgbCheck, 3, 1, 1, 1)
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setObjectName("label_5")
self.gridLayout_2.addWidget(self.label_5, 2, 0, 1, 1)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.framesSpin = QtWidgets.QSpinBox(self.centralwidget)
self.framesSpin.setButtonSymbols(QtWidgets.QAbstractSpinBox.ButtonSymbols.NoButtons)
self.framesSpin.setProperty("value", 10)
self.framesSpin.setObjectName("framesSpin")
self.horizontalLayout_4.addWidget(self.framesSpin)
self.widthSpin = QtWidgets.QSpinBox(self.centralwidget)
self.widthSpin.setButtonSymbols(QtWidgets.QAbstractSpinBox.ButtonSymbols.PlusMinus)
self.widthSpin.setMaximum(10000)
self.widthSpin.setProperty("value", 512)
self.widthSpin.setObjectName("widthSpin")
self.horizontalLayout_4.addWidget(self.widthSpin)
self.heightSpin = QtWidgets.QSpinBox(self.centralwidget)
self.heightSpin.setButtonSymbols(QtWidgets.QAbstractSpinBox.ButtonSymbols.NoButtons)
self.heightSpin.setMaximum(10000)
self.heightSpin.setProperty("value", 512)
self.heightSpin.setObjectName("heightSpin")
self.horizontalLayout_4.addWidget(self.heightSpin)
self.gridLayout_2.addLayout(self.horizontalLayout_4, 2, 1, 1, 2)
self.sizeLabel = QtWidgets.QLabel(self.centralwidget)
self.sizeLabel.setText("")
self.sizeLabel.setObjectName("sizeLabel")
self.gridLayout_2.addWidget(self.sizeLabel, 2, 3, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
self.stack.setCurrentIndex(1)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.cudaCheck.setText(_translate("MainWindow", "Use CUDA (GPU) if available"))
self.downsampleCheck.setText(_translate("MainWindow", "Auto downsample"))
self.scaleCheck.setText(_translate("MainWindow", "Scale Data"))
self.rawRadio.setText(_translate("MainWindow", "RawImageWidget"))
self.gfxRadio.setText(_translate("MainWindow", "GraphicsView + ImageItem"))
self.rawGLRadio.setText(_translate("MainWindow", "RawGLImageWidget"))
self.dtypeCombo.setItemText(0, _translate("MainWindow", "uint8"))
self.dtypeCombo.setItemText(1, _translate("MainWindow", "uint16"))
self.dtypeCombo.setItemText(2, _translate("MainWindow", "float"))
self.label.setText(_translate("MainWindow", "Data type"))
self.rgbLevelsCheck.setText(_translate("MainWindow", "RGB"))
self.label_3.setText(_translate("MainWindow", "<--->"))
self.label_2.setText(_translate("MainWindow", "<--->"))
self.label_4.setText(_translate("MainWindow", "<--->"))
self.lutCheck.setText(_translate("MainWindow", "Use Lookup Table"))
self.alphaCheck.setText(_translate("MainWindow", "alpha"))
self.fpsLabel.setText(_translate("MainWindow", "FPS"))
self.rgbCheck.setText(_translate("MainWindow", "RGB"))
self.label_5.setText(_translate("MainWindow", "Image size"))
from pyqtgraph import GradientWidget, GraphicsView, SpinBox
from pyqtgraph.widgets.RawImageWidget import RawImageWidget

View File

@ -27,6 +27,11 @@ class Ui_MainWindow(object):
self.centralwidget.setObjectName(u"centralwidget") self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout_2 = QGridLayout(self.centralwidget) self.gridLayout_2 = QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName(u"gridLayout_2") self.gridLayout_2.setObjectName(u"gridLayout_2")
self.cudaCheck = QCheckBox(self.centralwidget)
self.cudaCheck.setObjectName(u"cudaCheck")
self.gridLayout_2.addWidget(self.cudaCheck, 9, 0, 1, 2)
self.downsampleCheck = QCheckBox(self.centralwidget) self.downsampleCheck = QCheckBox(self.centralwidget)
self.downsampleCheck.setObjectName(u"downsampleCheck") self.downsampleCheck.setObjectName(u"downsampleCheck")
@ -258,6 +263,7 @@ class Ui_MainWindow(object):
def retranslateUi(self, MainWindow): def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None)) MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
self.cudaCheck.setText(QCoreApplication.translate("MainWindow", u"Use CUDA (GPU) if available", None))
self.downsampleCheck.setText(QCoreApplication.translate("MainWindow", u"Auto downsample", None)) self.downsampleCheck.setText(QCoreApplication.translate("MainWindow", u"Auto downsample", None))
self.scaleCheck.setText(QCoreApplication.translate("MainWindow", u"Scale Data", None)) self.scaleCheck.setText(QCoreApplication.translate("MainWindow", u"Scale Data", None))
self.rawRadio.setText(QCoreApplication.translate("MainWindow", u"RawImageWidget", None)) self.rawRadio.setText(QCoreApplication.translate("MainWindow", u"RawImageWidget", None))

View File

@ -0,0 +1,32 @@
# Form implementation generated from reading ui file 'examples\designerExample.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setObjectName("gridLayout")
self.plotBtn = QtWidgets.QPushButton(Form)
self.plotBtn.setObjectName("plotBtn")
self.gridLayout.addWidget(self.plotBtn, 0, 0, 1, 1)
self.plot = PlotWidget(Form)
self.plot.setObjectName("plot")
self.gridLayout.addWidget(self.plot, 1, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.plotBtn.setText(_translate("Form", "Plot!"))
from pyqtgraph import PlotWidget

View File

@ -0,0 +1,93 @@
# Form implementation generated from reading ui file 'examples\exampleLoaderTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(846, 552)
self.gridLayout_2 = QtWidgets.QGridLayout(Form)
self.gridLayout_2.setObjectName("gridLayout_2")
self.splitter = QtWidgets.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Orientations.Horizontal)
self.splitter.setObjectName("splitter")
self.widget = QtWidgets.QWidget(self.splitter)
self.widget.setObjectName("widget")
self.gridLayout = QtWidgets.QGridLayout(self.widget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.exampleTree = QtWidgets.QTreeWidget(self.widget)
self.exampleTree.setObjectName("exampleTree")
self.exampleTree.headerItem().setText(0, "1")
self.exampleTree.header().setVisible(False)
self.gridLayout.addWidget(self.exampleTree, 0, 0, 1, 2)
self.graphicsSystemCombo = QtWidgets.QComboBox(self.widget)
self.graphicsSystemCombo.setObjectName("graphicsSystemCombo")
self.graphicsSystemCombo.addItem("")
self.graphicsSystemCombo.addItem("")
self.graphicsSystemCombo.addItem("")
self.graphicsSystemCombo.addItem("")
self.gridLayout.addWidget(self.graphicsSystemCombo, 2, 1, 1, 1)
self.qtLibCombo = QtWidgets.QComboBox(self.widget)
self.qtLibCombo.setObjectName("qtLibCombo")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.gridLayout.addWidget(self.qtLibCombo, 1, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(self.widget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
self.label = QtWidgets.QLabel(self.widget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
self.loadBtn = QtWidgets.QPushButton(self.widget)
self.loadBtn.setObjectName("loadBtn")
self.gridLayout.addWidget(self.loadBtn, 3, 1, 1, 1)
self.widget1 = QtWidgets.QWidget(self.splitter)
self.widget1.setObjectName("widget1")
self.verticalLayout = QtWidgets.QVBoxLayout(self.widget1)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.loadedFileLabel = QtWidgets.QLabel(self.widget1)
font = QtGui.QFont()
font.setBold(True)
self.loadedFileLabel.setFont(font)
self.loadedFileLabel.setText("")
self.loadedFileLabel.setAlignment(QtCore.Qt.Alignment.AlignCenter)
self.loadedFileLabel.setObjectName("loadedFileLabel")
self.verticalLayout.addWidget(self.loadedFileLabel)
self.codeView = QtWidgets.QPlainTextEdit(self.widget1)
font = QtGui.QFont()
font.setFamily("Courier New")
self.codeView.setFont(font)
self.codeView.setObjectName("codeView")
self.verticalLayout.addWidget(self.codeView)
self.gridLayout_2.addWidget(self.splitter, 0, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.graphicsSystemCombo.setItemText(0, _translate("Form", "default"))
self.graphicsSystemCombo.setItemText(1, _translate("Form", "native"))
self.graphicsSystemCombo.setItemText(2, _translate("Form", "raster"))
self.graphicsSystemCombo.setItemText(3, _translate("Form", "opengl"))
self.qtLibCombo.setItemText(0, _translate("Form", "default"))
self.qtLibCombo.setItemText(1, _translate("Form", "PyQt4"))
self.qtLibCombo.setItemText(2, _translate("Form", "PySide"))
self.qtLibCombo.setItemText(3, _translate("Form", "PyQt5"))
self.qtLibCombo.setItemText(4, _translate("Form", "PySide2"))
self.label_2.setText(_translate("Form", "Graphics System:"))
self.label.setText(_translate("Form", "Qt Library:"))
self.loadBtn.setText(_translate("Form", "Run Example"))

View File

@ -35,10 +35,10 @@ def buildFileList(examples, files=None):
path = os.path.abspath(os.path.dirname(__file__)) path = os.path.abspath(os.path.dirname(__file__))
files = sorted(set(buildFileList(examples))) files = sorted(set(buildFileList(examples)))
frontends = { frontends = {
Qt.PYQT4: False,
Qt.PYQT5: False, Qt.PYQT5: False,
Qt.PYSIDE: False, Qt.PYQT6: False,
Qt.PYSIDE2: False Qt.PYSIDE2: False,
Qt.PYSIDE6: False,
} }
# sort out which of the front ends are available # sort out which of the front ends are available
for frontend in frontends.keys(): for frontend in frontends.keys():
@ -66,13 +66,6 @@ conditionalExamples = {
False, False,
reason="Test is being problematic on CI machines" reason="Test is being problematic on CI machines"
), ),
"optics_demos.py": exceptionCondition(
not frontends[Qt.PYSIDE],
reason=(
"Test fails due to PySide bug: ",
"https://bugreports.qt.io/browse/PYSIDE-671"
)
),
'GLVolumeItem.py': exceptionCondition( 'GLVolumeItem.py': exceptionCondition(
not(platform.system() == "Darwin" and not(platform.system() == "Darwin" and
tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and

View File

@ -3,7 +3,7 @@ import time
import weakref import weakref
import warnings import warnings
from ..Qt import QtCore, QtGui, isQObjectAlive from ..Qt import QtCore, QtGui, QT_LIB, isQObjectAlive
from ..Point import Point from ..Point import Point
from .. import functions as fn from .. import functions as fn
from .. import ptime as ptime from .. import ptime as ptime
@ -14,15 +14,9 @@ from .. import getConfigOption
getMillis = lambda: int(round(time.time() * 1000)) getMillis = lambda: int(round(time.time() * 1000))
if hasattr(QtCore, 'PYQT_VERSION'): if QT_LIB.startswith('PyQt'):
try: from ..Qt import sip
try: HAVE_SIP = True
from PyQt5 import sip
except ImportError:
import sip
HAVE_SIP = True
except ImportError:
HAVE_SIP = False
else: else:
HAVE_SIP = False HAVE_SIP = False
@ -158,7 +152,7 @@ class GraphicsScene(QtGui.QGraphicsScene):
self._moveDistance = d self._moveDistance = d
def mousePressEvent(self, ev): def mousePressEvent(self, ev):
QtGui.QGraphicsScene.mousePressEvent(self, ev) super().mousePressEvent(ev)
if self.mouseGrabberItem() is None: ## nobody claimed press; we are free to generate drag/click events if self.mouseGrabberItem() is None: ## nobody claimed press; we are free to generate drag/click events
if self.lastHoverEvent is not None: if self.lastHoverEvent is not None:
# If the mouse has moved since the last hover event, send a new one. # If the mouse has moved since the last hover event, send a new one.
@ -171,7 +165,7 @@ class GraphicsScene(QtGui.QGraphicsScene):
## set focus on the topmost focusable item under this click ## set focus on the topmost focusable item under this click
items = self.items(ev.scenePos()) items = self.items(ev.scenePos())
for i in items: for i in items:
if i.isEnabled() and i.isVisible() and int(i.flags() & i.ItemIsFocusable) > 0: if i.isEnabled() and i.isVisible() and (i.flags() & i.ItemIsFocusable):
i.setFocus(QtCore.Qt.MouseFocusReason) i.setFocus(QtCore.Qt.MouseFocusReason)
break break
@ -197,35 +191,35 @@ class GraphicsScene(QtGui.QGraphicsScene):
self.sigMouseMoved.emit(ev.scenePos()) self.sigMouseMoved.emit(ev.scenePos())
# First allow QGraphicsScene to eliver hoverEvent/Move/Exit Events # First allow QGraphicsScene to eliver hoverEvent/Move/Exit Events
QtGui.QGraphicsScene.mouseMoveEvent(self, ev) super().mouseMoveEvent(ev)
# Next Deliver our own Hover Events # Next Deliver our own Hover Events
self.sendHoverEvents(ev) self.sendHoverEvents(ev)
if int(ev.buttons()) != 0: if ev.buttons():
# button is pressed' send mouseMoveEvents and mouseDragEvents # button is pressed' send mouseMoveEvents and mouseDragEvents
QtGui.QGraphicsScene.mouseMoveEvent(self, ev) super().mouseMoveEvent(ev)
if self.mouseGrabberItem() is None: if self.mouseGrabberItem() is None:
now = ptime.time() now = ptime.time()
init = False init = False
## keep track of which buttons are involved in dragging ## keep track of which buttons are involved in dragging
for btn in [QtCore.Qt.LeftButton, QtCore.Qt.MiddleButton, QtCore.Qt.RightButton]: for btn in [QtCore.Qt.LeftButton, QtCore.Qt.MiddleButton, QtCore.Qt.RightButton]:
if int(ev.buttons() & btn) == 0: if not (ev.buttons() & btn):
continue continue
if int(btn) not in self.dragButtons: ## see if we've dragged far enough yet if btn not in self.dragButtons: ## see if we've dragged far enough yet
cev = [e for e in self.clickEvents if int(e.button()) == int(btn)] cev = [e for e in self.clickEvents if e.button() == btn]
if cev: if cev:
cev = cev[0] cev = cev[0]
dist = Point(ev.scenePos() - cev.scenePos()).length() dist = Point(ev.scenePos() - cev.scenePos()).length()
if dist == 0 or (dist < self._moveDistance and now - cev.time() < self.minDragTime): if dist == 0 or (dist < self._moveDistance and now - cev.time() < self.minDragTime):
continue continue
init = init or (len(self.dragButtons) == 0) ## If this is the first button to be dragged, then init=True init = init or (len(self.dragButtons) == 0) ## If this is the first button to be dragged, then init=True
self.dragButtons.append(int(btn)) self.dragButtons.append(btn)
## if we have dragged buttons, deliver a drag event ## if we have dragged buttons, deliver a drag event
if len(self.dragButtons) > 0: if len(self.dragButtons) > 0:
if self.sendDragEvent(ev, init=init): if self.sendDragEvent(ev, init=init):
ev.accept() ev.accept()
else: else:
QtGui.QGraphicsScene.mouseMoveEvent(self, ev) super().mouseMoveEvent(ev)
# if you do not accept event (which is ignored) then cursor will disappear # if you do not accept event (which is ignored) then cursor will disappear
ev.accept() ev.accept()
@ -241,24 +235,24 @@ class GraphicsScene(QtGui.QGraphicsScene):
ev.accept() ev.accept()
self.dragButtons.remove(ev.button()) self.dragButtons.remove(ev.button())
else: else:
cev = [e for e in self.clickEvents if int(e.button()) == int(ev.button())] cev = [e for e in self.clickEvents if e.button() == ev.button()]
if cev: if cev:
if self.sendClickEvent(cev[0]): if self.sendClickEvent(cev[0]):
#print "sent click event" #print "sent click event"
ev.accept() ev.accept()
self.clickEvents.remove(cev[0]) self.clickEvents.remove(cev[0])
if int(ev.buttons()) == 0: if not ev.buttons():
self.dragItem = None self.dragItem = None
self.dragButtons = [] self.dragButtons = []
self.clickEvents = [] self.clickEvents = []
self.lastDrag = None self.lastDrag = None
QtGui.QGraphicsScene.mouseReleaseEvent(self, ev) super().mouseReleaseEvent(ev)
self.sendHoverEvents(ev) ## let items prepare for next click/drag self.sendHoverEvents(ev) ## let items prepare for next click/drag
def mouseDoubleClickEvent(self, ev): def mouseDoubleClickEvent(self, ev):
QtGui.QGraphicsScene.mouseDoubleClickEvent(self, ev) super().mouseDoubleClickEvent(ev)
if self.mouseGrabberItem() is None: ## nobody claimed press; we are free to generate drag/click events if self.mouseGrabberItem() is None: ## nobody claimed press; we are free to generate drag/click events
self.clickEvents.append(MouseClickEvent(ev, double=True)) self.clickEvents.append(MouseClickEvent(ev, double=True))
@ -270,7 +264,7 @@ class GraphicsScene(QtGui.QGraphicsScene):
items = [] items = []
event = HoverEvent(None, acceptable) event = HoverEvent(None, acceptable)
else: else:
acceptable = int(ev.buttons()) == 0 ## if we are in mid-drag, do not allow items to accept the hover event. acceptable = not ev.buttons() ## if we are in mid-drag, do not allow items to accept the hover event.
event = HoverEvent(ev, acceptable) event = HoverEvent(ev, acceptable)
items = self.itemsNearEvent(event, hoverable=True) items = self.itemsNearEvent(event, hoverable=True)
self.sigMouseHover.emit(items) self.sigMouseHover.emit(items)
@ -312,7 +306,7 @@ class GraphicsScene(QtGui.QGraphicsScene):
# item to continue receiving events until the drag is over # item to continue receiving events until the drag is over
# - event is not a mouse event (QEvent.Leave sometimes appears here) # - event is not a mouse event (QEvent.Leave sometimes appears here)
if (ev.type() == ev.GraphicsSceneMousePress or if (ev.type() == ev.GraphicsSceneMousePress or
(ev.type() == ev.GraphicsSceneMouseMove and int(ev.buttons()) == 0)): (ev.type() == ev.GraphicsSceneMouseMove and not ev.buttons())):
self.lastHoverEvent = event ## save this so we can ask about accepted events later. self.lastHoverEvent = event ## save this so we can ask about accepted events later.
def sendDragEvent(self, ev, init=False, final=False): def sendDragEvent(self, ev, init=False, final=False):
@ -350,7 +344,7 @@ class GraphicsScene(QtGui.QGraphicsScene):
if event.isAccepted(): if event.isAccepted():
#print " --> accepted" #print " --> accepted"
self.dragItem = item self.dragItem = item
if int(item.flags() & item.ItemIsFocusable) > 0: if item.flags() & item.ItemIsFocusable:
item.setFocus(QtCore.Qt.MouseFocusReason) item.setFocus(QtCore.Qt.MouseFocusReason)
break break
elif self.dragItem is not None: elif self.dragItem is not None:
@ -395,7 +389,7 @@ class GraphicsScene(QtGui.QGraphicsScene):
debug.printExc("Error sending click event:") debug.printExc("Error sending click event:")
if ev.isAccepted(): if ev.isAccepted():
if int(item.flags() & item.ItemIsFocusable) > 0: if item.flags() & item.ItemIsFocusable:
item.setFocus(QtCore.Qt.MouseFocusReason) item.setFocus(QtCore.Qt.MouseFocusReason)
break break
self.sigMouseClicked.emit(ev) self.sigMouseClicked.emit(ev)

View File

@ -140,4 +140,4 @@ class ExportDialog(QtGui.QWidget):
def closeEvent(self, event): def closeEvent(self, event):
self.close() self.close()
QtGui.QWidget.closeEvent(self, event) super().closeEvent(event)

View File

@ -0,0 +1,63 @@
# Form implementation generated from reading ui file 'pyqtgraph\GraphicsScene\exportDialogTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(241, 367)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(Form)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 3)
self.itemTree = QtWidgets.QTreeWidget(Form)
self.itemTree.setObjectName("itemTree")
self.itemTree.headerItem().setText(0, "1")
self.itemTree.header().setVisible(False)
self.gridLayout.addWidget(self.itemTree, 1, 0, 1, 3)
self.label_2 = QtWidgets.QLabel(Form)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 3)
self.formatList = QtWidgets.QListWidget(Form)
self.formatList.setObjectName("formatList")
self.gridLayout.addWidget(self.formatList, 3, 0, 1, 3)
self.exportBtn = QtWidgets.QPushButton(Form)
self.exportBtn.setObjectName("exportBtn")
self.gridLayout.addWidget(self.exportBtn, 6, 1, 1, 1)
self.closeBtn = QtWidgets.QPushButton(Form)
self.closeBtn.setObjectName("closeBtn")
self.gridLayout.addWidget(self.closeBtn, 6, 2, 1, 1)
self.paramTree = ParameterTree(Form)
self.paramTree.setObjectName("paramTree")
self.paramTree.headerItem().setText(0, "1")
self.paramTree.header().setVisible(False)
self.gridLayout.addWidget(self.paramTree, 5, 0, 1, 3)
self.label_3 = QtWidgets.QLabel(Form)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 4, 0, 1, 3)
self.copyBtn = QtWidgets.QPushButton(Form)
self.copyBtn.setObjectName("copyBtn")
self.gridLayout.addWidget(self.copyBtn, 6, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Export"))
self.label.setText(_translate("Form", "Item to export:"))
self.label_2.setText(_translate("Form", "Export format"))
self.exportBtn.setText(_translate("Form", "Export"))
self.closeBtn.setText(_translate("Form", "Close"))
self.label_3.setText(_translate("Form", "Export options"))
self.copyBtn.setText(_translate("Form", "Copy"))
from ..parametertree import ParameterTree

View File

@ -19,8 +19,8 @@ class MouseDragEvent(object):
self._buttonDownScenePos = {} self._buttonDownScenePos = {}
self._buttonDownScreenPos = {} self._buttonDownScreenPos = {}
for btn in [QtCore.Qt.LeftButton, QtCore.Qt.MiddleButton, QtCore.Qt.RightButton]: for btn in [QtCore.Qt.LeftButton, QtCore.Qt.MiddleButton, QtCore.Qt.RightButton]:
self._buttonDownScenePos[int(btn)] = moveEvent.buttonDownScenePos(btn) self._buttonDownScenePos[btn] = moveEvent.buttonDownScenePos(btn)
self._buttonDownScreenPos[int(btn)] = moveEvent.buttonDownScreenPos(btn) self._buttonDownScreenPos[btn] = moveEvent.buttonDownScreenPos(btn)
self._scenePos = moveEvent.scenePos() self._scenePos = moveEvent.scenePos()
self._screenPos = moveEvent.screenPos() self._screenPos = moveEvent.screenPos()
if lastEvent is None: if lastEvent is None:
@ -61,7 +61,7 @@ class MouseDragEvent(object):
""" """
if btn is None: if btn is None:
btn = self.button() btn = self.button()
return Point(self._buttonDownScenePos[int(btn)]) return Point(self._buttonDownScenePos[btn])
def buttonDownScreenPos(self, btn=None): def buttonDownScreenPos(self, btn=None):
""" """
@ -70,7 +70,7 @@ class MouseDragEvent(object):
""" """
if btn is None: if btn is None:
btn = self.button() btn = self.button()
return Point(self._buttonDownScreenPos[int(btn)]) return Point(self._buttonDownScreenPos[btn])
def lastScenePos(self): def lastScenePos(self):
""" """
@ -119,7 +119,7 @@ class MouseDragEvent(object):
""" """
if btn is None: if btn is None:
btn = self.button() btn = self.button()
return Point(self.currentItem.mapFromScene(self._buttonDownScenePos[int(btn)])) return Point(self.currentItem.mapFromScene(self._buttonDownScenePos[btn]))
def isStart(self): def isStart(self):
"""Returns True if this event is the first since a drag was initiated.""" """Returns True if this event is the first since a drag was initiated."""
@ -137,7 +137,7 @@ class MouseDragEvent(object):
else: else:
lp = self.lastPos() lp = self.lastPos()
p = self.pos() p = self.pos()
return "<MouseDragEvent (%g,%g)->(%g,%g) buttons=%d start=%s finish=%s>" % (lp.x(), lp.y(), p.x(), p.y(), int(self.buttons()), str(self.isStart()), str(self.isFinish())) return "<MouseDragEvent (%g,%g)->(%g,%g) buttons=%s start=%s finish=%s>" % (lp.x(), lp.y(), p.x(), p.y(), str(self.buttons()), str(self.isStart()), str(self.isFinish()))
def modifiers(self): def modifiers(self):
"""Return any keyboard modifiers currently pressed. """Return any keyboard modifiers currently pressed.
@ -230,9 +230,9 @@ class MouseClickEvent(object):
p = self._scenePos p = self._scenePos
else: else:
p = self.pos() p = self.pos()
return "<MouseClickEvent (%g,%g) button=%d>" % (p.x(), p.y(), int(self.button())) return "<MouseClickEvent (%g,%g) button=%s>" % (p.x(), p.y(), str(self.button()))
except: except:
return "<MouseClickEvent button=%d>" % (int(self.button())) return "<MouseClickEvent button=%s>" % (str(self.button()))
def time(self): def time(self):
return self._time return self._time
@ -362,7 +362,7 @@ class HoverEvent(object):
else: else:
lp = self.lastPos() lp = self.lastPos()
p = self.pos() p = self.pos()
return "<HoverEvent (%g,%g)->(%g,%g) buttons=%d enter=%s exit=%s>" % (lp.x(), lp.y(), p.x(), p.y(), int(self.buttons()), str(self.isEnter()), str(self.isExit())) return "<HoverEvent (%g,%g)->(%g,%g) buttons=%s enter=%s exit=%s>" % (lp.x(), lp.y(), p.x(), p.y(), str(self.buttons()), str(self.isEnter()), str(self.isExit()))
def modifiers(self): def modifiers(self):
"""Return any keyboard modifiers currently pressed. """Return any keyboard modifiers currently pressed.

View File

@ -11,6 +11,8 @@ This module exists to smooth out some of the differences between PySide and PyQt
""" """
import os, sys, re, time, subprocess, warnings import os, sys, re, time, subprocess, warnings
import importlib
import enum
from .python2_3 import asUnicode from .python2_3 import asUnicode
@ -28,7 +30,7 @@ QT_LIB = os.getenv('PYQTGRAPH_QT_LIB')
## This is done by first checking to see whether one of the libraries ## 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. ## is already imported. If not, then attempt to import PyQt4, then PySide.
if QT_LIB is None: if QT_LIB is None:
libOrder = [PYQT4, PYSIDE, PYQT5, PYSIDE2, PYSIDE6] libOrder = [PYQT4, PYSIDE, PYQT5, PYSIDE2, PYSIDE6, PYQT6]
for lib in libOrder: for lib in libOrder:
if lib in sys.modules: if lib in sys.modules:
@ -45,7 +47,7 @@ if QT_LIB is None:
pass pass
if QT_LIB is None: if QT_LIB is None:
raise Exception("PyQtGraph requires one of PyQt4, PyQt5, PySide, PySide2 or PySide6; none of these packages could be imported.") raise Exception("PyQtGraph requires one of PyQt4, PyQt5, PyQt6, PySide, PySide2 or PySide6; none of these packages could be imported.")
class FailedImport(object): class FailedImport(object):
@ -221,6 +223,25 @@ elif QT_LIB == PYQT5:
VERSION_INFO = 'PyQt5 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR VERSION_INFO = 'PyQt5 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
elif QT_LIB == PYQT6:
from PyQt6 import QtGui, QtCore, QtWidgets, 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
QtTest.QTest.qWaitForWindowShown = QtTest.QTest.qWaitForWindowExposed
except ImportError as err:
QtTest = FailedImport(err)
VERSION_INFO = 'PyQt6 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
elif QT_LIB == PYSIDE2: elif QT_LIB == PYSIDE2:
from PySide2 import QtGui, QtCore, QtWidgets from PySide2 import QtGui, QtCore, QtWidgets
@ -277,8 +298,8 @@ else:
raise ValueError("Invalid Qt lib '%s'" % QT_LIB) raise ValueError("Invalid Qt lib '%s'" % QT_LIB)
# common to PyQt5, PySide2 and PySide6 # common to PyQt5, PyQt6, PySide2 and PySide6
if QT_LIB in [PYQT5, PYSIDE2, PYSIDE6]: if QT_LIB in [PYQT5, PYQT6, PYSIDE2, PYSIDE6]:
# We're using Qt5 which has a different structure so we're going to use a shim to # We're using Qt5 which has a different structure so we're going to use a shim to
# recreate the Qt4 structure # recreate the Qt4 structure
@ -353,13 +374,13 @@ if QT_LIB in [PYSIDE, PYSIDE2, PYSIDE6]:
QtTest.QTest.qWait = qWait QtTest.QTest.qWait = qWait
# Common to PyQt4 and 5 # Common to PyQt4, PyQt5 and PyQt6
if QT_LIB in [PYQT4, PYQT5]: if QT_LIB in [PYQT4, PYQT5, PYQT6]:
QtVersion = QtCore.QT_VERSION_STR QtVersion = QtCore.QT_VERSION_STR
try: try:
from PyQt5 import sip sip = importlib.import_module(QT_LIB + '.sip')
except ImportError: except ModuleNotFoundError:
import sip import sip
def isQObjectAlive(obj): def isQObjectAlive(obj):
return not sip.isdeleted(obj) return not sip.isdeleted(obj)
@ -369,6 +390,67 @@ if QT_LIB in [PYQT4, PYQT5]:
QtCore.Signal = QtCore.pyqtSignal QtCore.Signal = QtCore.pyqtSignal
if QT_LIB == PYSIDE6:
# PySide6 6.0 has a missing binding
if not hasattr(QtGui.QGradient, 'setStops'):
def __setStops(self, stops):
for pos, color in stops:
self.setColorAt(pos, color)
QtGui.QGradient.setStops = __setStops
if QT_LIB == PYQT6:
# module.Class.EnumClass.Enum -> module.Class.Enum
def promote_enums(module):
class_names = [x for x in dir(module) if x[0] == 'Q']
for class_name in class_names:
klass = getattr(module, class_name)
if not isinstance(klass, sip.wrappertype):
continue
attrib_names = [x for x in dir(klass) if x[0].isupper()]
for attrib_name in attrib_names:
attrib = getattr(klass, attrib_name)
if not isinstance(attrib, enum.EnumMeta):
continue
for e in attrib:
setattr(klass, e.name, e)
promote_enums(QtCore)
promote_enums(QtGui)
promote_enums(QtWidgets)
# QKeyEvent::key() returns an int
# so comparison with a Key_* enum will always be False
# here we convert the enum to its int value
for e in QtCore.Qt.Key:
setattr(QtCore.Qt, e.name, e.value)
# shim the old names for QPointF mouse coords
QtGui.QSinglePointEvent.localPos = lambda o : o.position()
QtGui.QSinglePointEvent.windowPos = lambda o : o.scenePosition()
QtGui.QSinglePointEvent.screenPos = lambda o : o.globalPosition()
QtGui.QDropEvent.posF = lambda o : o.position()
QtWidgets.QApplication.exec_ = QtWidgets.QApplication.exec
QtWidgets.QDialog.exec_ = lambda o : o.exec()
QtGui.QDrag.exec_ = lambda o : o.exec()
# PyQt6 6.0.0 has a bug where it can't handle certain Type values returned
# by the Qt library.
try:
# 213 is a known failing value
QtCore.QEvent.Type(213)
except ValueError:
def new_method(self, old_method=QtCore.QEvent.type):
try:
typ = old_method(self)
except ValueError:
typ = QtCore.QEvent.Type.None_
return typ
QtCore.QEvent.type = new_method
del new_method
# USE_XXX variables are deprecated # USE_XXX variables are deprecated
USE_PYSIDE = QT_LIB == PYSIDE USE_PYSIDE = QT_LIB == PYSIDE
USE_PYQT4 = QT_LIB == PYQT4 USE_PYQT4 = QT_LIB == PYQT4

View File

@ -218,9 +218,6 @@ class WidgetGroup(QtCore.QObject):
v1 = self.cache[n] v1 = self.cache[n]
v2 = self.readWidget(w) v2 = self.readWidget(w)
if v1 != v2: if v1 != v2:
if QT_LIB != 'PyQt5':
# Old signal kept for backward compatibility.
self.emit(QtCore.SIGNAL('changed'), self.widgetList[w], v2)
self.sigChanged.emit(self.widgetList[w], v2) self.sigChanged.emit(self.widgetList[w], v2)
def state(self): def state(self):

View File

@ -107,7 +107,7 @@ class Canvas(QtGui.QWidget):
def resizeEvent(self, ev=None): def resizeEvent(self, ev=None):
if ev is not None: if ev is not None:
QtGui.QWidget.resizeEvent(self, ev) super().resizeEvent(ev)
self.hideBtn.move(self.ui.view.size().width() - self.hideBtn.width(), 0) self.hideBtn.move(self.ui.view.size().width() - self.hideBtn.width(), 0)
if not self.sizeApplied: if not self.sizeApplied:

View File

@ -0,0 +1,92 @@
# Form implementation generated from reading ui file 'pyqtgraph\canvas\CanvasTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(821, 578)
self.gridLayout_2 = QtWidgets.QGridLayout(Form)
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
self.gridLayout_2.setSpacing(0)
self.gridLayout_2.setObjectName("gridLayout_2")
self.splitter = QtWidgets.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Orientations.Horizontal)
self.splitter.setObjectName("splitter")
self.view = GraphicsView(self.splitter)
self.view.setObjectName("view")
self.vsplitter = QtWidgets.QSplitter(self.splitter)
self.vsplitter.setOrientation(QtCore.Qt.Orientations.Vertical)
self.vsplitter.setObjectName("vsplitter")
self.canvasCtrlWidget = QtWidgets.QWidget(self.vsplitter)
self.canvasCtrlWidget.setObjectName("canvasCtrlWidget")
self.gridLayout = QtWidgets.QGridLayout(self.canvasCtrlWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.autoRangeBtn = QtWidgets.QPushButton(self.canvasCtrlWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.autoRangeBtn.sizePolicy().hasHeightForWidth())
self.autoRangeBtn.setSizePolicy(sizePolicy)
self.autoRangeBtn.setObjectName("autoRangeBtn")
self.gridLayout.addWidget(self.autoRangeBtn, 0, 0, 1, 2)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.redirectCheck = QtWidgets.QCheckBox(self.canvasCtrlWidget)
self.redirectCheck.setObjectName("redirectCheck")
self.horizontalLayout.addWidget(self.redirectCheck)
self.redirectCombo = CanvasCombo(self.canvasCtrlWidget)
self.redirectCombo.setObjectName("redirectCombo")
self.horizontalLayout.addWidget(self.redirectCombo)
self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 2)
self.itemList = TreeWidget(self.canvasCtrlWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(100)
sizePolicy.setHeightForWidth(self.itemList.sizePolicy().hasHeightForWidth())
self.itemList.setSizePolicy(sizePolicy)
self.itemList.setHeaderHidden(True)
self.itemList.setObjectName("itemList")
self.itemList.headerItem().setText(0, "1")
self.gridLayout.addWidget(self.itemList, 2, 0, 1, 2)
self.resetTransformsBtn = QtWidgets.QPushButton(self.canvasCtrlWidget)
self.resetTransformsBtn.setObjectName("resetTransformsBtn")
self.gridLayout.addWidget(self.resetTransformsBtn, 3, 0, 1, 2)
self.mirrorSelectionBtn = QtWidgets.QPushButton(self.canvasCtrlWidget)
self.mirrorSelectionBtn.setObjectName("mirrorSelectionBtn")
self.gridLayout.addWidget(self.mirrorSelectionBtn, 4, 0, 1, 1)
self.reflectSelectionBtn = QtWidgets.QPushButton(self.canvasCtrlWidget)
self.reflectSelectionBtn.setObjectName("reflectSelectionBtn")
self.gridLayout.addWidget(self.reflectSelectionBtn, 4, 1, 1, 1)
self.canvasItemCtrl = QtWidgets.QWidget(self.vsplitter)
self.canvasItemCtrl.setObjectName("canvasItemCtrl")
self.ctrlLayout = QtWidgets.QGridLayout(self.canvasItemCtrl)
self.ctrlLayout.setContentsMargins(0, 0, 0, 0)
self.ctrlLayout.setSpacing(0)
self.ctrlLayout.setObjectName("ctrlLayout")
self.gridLayout_2.addWidget(self.splitter, 0, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.autoRangeBtn.setText(_translate("Form", "Auto Range"))
self.redirectCheck.setToolTip(_translate("Form", "Check to display all local items in a remote canvas."))
self.redirectCheck.setText(_translate("Form", "Redirect"))
self.resetTransformsBtn.setText(_translate("Form", "Reset Transforms"))
self.mirrorSelectionBtn.setText(_translate("Form", "Mirror Selection"))
self.reflectSelectionBtn.setText(_translate("Form", "MirrorXY"))
from ..widgets.GraphicsView import GraphicsView
from ..widgets.TreeWidget import TreeWidget
from .CanvasManager import CanvasCombo

View File

@ -0,0 +1,55 @@
# Form implementation generated from reading ui file 'pyqtgraph\canvas\TransformGuiTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(224, 117)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth())
Form.setSizePolicy(sizePolicy)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(1)
self.verticalLayout.setObjectName("verticalLayout")
self.translateLabel = QtWidgets.QLabel(Form)
self.translateLabel.setObjectName("translateLabel")
self.verticalLayout.addWidget(self.translateLabel)
self.rotateLabel = QtWidgets.QLabel(Form)
self.rotateLabel.setObjectName("rotateLabel")
self.verticalLayout.addWidget(self.rotateLabel)
self.scaleLabel = QtWidgets.QLabel(Form)
self.scaleLabel.setObjectName("scaleLabel")
self.verticalLayout.addWidget(self.scaleLabel)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.mirrorImageBtn = QtWidgets.QPushButton(Form)
self.mirrorImageBtn.setToolTip("")
self.mirrorImageBtn.setObjectName("mirrorImageBtn")
self.horizontalLayout.addWidget(self.mirrorImageBtn)
self.reflectImageBtn = QtWidgets.QPushButton(Form)
self.reflectImageBtn.setObjectName("reflectImageBtn")
self.horizontalLayout.addWidget(self.reflectImageBtn)
self.verticalLayout.addLayout(self.horizontalLayout)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.translateLabel.setText(_translate("Form", "Translate:"))
self.rotateLabel.setText(_translate("Form", "Rotate:"))
self.scaleLabel.setText(_translate("Form", "Scale:"))
self.mirrorImageBtn.setText(_translate("Form", "Mirror"))
self.reflectImageBtn.setText(_translate("Form", "Reflect"))

View File

@ -359,13 +359,7 @@ class ColorMap(object):
pos, color = self.getStops(mode=self.BYTE) pos, color = self.getStops(mode=self.BYTE)
color = [QtGui.QColor(*x) for x in color] color = [QtGui.QColor(*x) for x in color]
stops = zip(pos, color) g.setStops(list(zip(pos, color)))
if hasattr(g, 'setStops'):
g.setStops(list(stops))
else:
# PySide6 has a missing setStops binding
for pos, col in stops:
g.setColorAt(pos, col)
return g return g
def getColors(self, mode=None): def getColors(self, mode=None):

View File

@ -24,7 +24,7 @@ class CmdInput(QtGui.QLineEdit):
elif ev.key() == QtCore.Qt.Key_Return: elif ev.key() == QtCore.Qt.Key_Return:
self.execCmd() self.execCmd()
else: else:
QtGui.QLineEdit.keyPressEvent(self, ev) super().keyPressEvent(ev)
self.history[0] = asUnicode(self.text()) self.history[0] = asUnicode(self.text())
def execCmd(self): def execCmd(self):

View File

@ -0,0 +1,115 @@
# Form implementation generated from reading ui file 'pyqtgraph\console\template.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(739, 497)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.splitter = QtWidgets.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Orientations.Vertical)
self.splitter.setObjectName("splitter")
self.layoutWidget = QtWidgets.QWidget(self.splitter)
self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.output = QtWidgets.QPlainTextEdit(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("Monospace")
self.output.setFont(font)
self.output.setReadOnly(True)
self.output.setObjectName("output")
self.verticalLayout.addWidget(self.output)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.input = CmdInput(self.layoutWidget)
self.input.setObjectName("input")
self.horizontalLayout.addWidget(self.input)
self.historyBtn = QtWidgets.QPushButton(self.layoutWidget)
self.historyBtn.setCheckable(True)
self.historyBtn.setObjectName("historyBtn")
self.horizontalLayout.addWidget(self.historyBtn)
self.exceptionBtn = QtWidgets.QPushButton(self.layoutWidget)
self.exceptionBtn.setCheckable(True)
self.exceptionBtn.setObjectName("exceptionBtn")
self.horizontalLayout.addWidget(self.exceptionBtn)
self.verticalLayout.addLayout(self.horizontalLayout)
self.historyList = QtWidgets.QListWidget(self.splitter)
font = QtGui.QFont()
font.setFamily("Monospace")
self.historyList.setFont(font)
self.historyList.setObjectName("historyList")
self.exceptionGroup = QtWidgets.QGroupBox(self.splitter)
self.exceptionGroup.setObjectName("exceptionGroup")
self.gridLayout_2 = QtWidgets.QGridLayout(self.exceptionGroup)
self.gridLayout_2.setContentsMargins(-1, 0, -1, 0)
self.gridLayout_2.setHorizontalSpacing(2)
self.gridLayout_2.setVerticalSpacing(0)
self.gridLayout_2.setObjectName("gridLayout_2")
self.clearExceptionBtn = QtWidgets.QPushButton(self.exceptionGroup)
self.clearExceptionBtn.setEnabled(False)
self.clearExceptionBtn.setObjectName("clearExceptionBtn")
self.gridLayout_2.addWidget(self.clearExceptionBtn, 0, 6, 1, 1)
self.catchAllExceptionsBtn = QtWidgets.QPushButton(self.exceptionGroup)
self.catchAllExceptionsBtn.setCheckable(True)
self.catchAllExceptionsBtn.setObjectName("catchAllExceptionsBtn")
self.gridLayout_2.addWidget(self.catchAllExceptionsBtn, 0, 1, 1, 1)
self.catchNextExceptionBtn = QtWidgets.QPushButton(self.exceptionGroup)
self.catchNextExceptionBtn.setCheckable(True)
self.catchNextExceptionBtn.setObjectName("catchNextExceptionBtn")
self.gridLayout_2.addWidget(self.catchNextExceptionBtn, 0, 0, 1, 1)
self.onlyUncaughtCheck = QtWidgets.QCheckBox(self.exceptionGroup)
self.onlyUncaughtCheck.setChecked(True)
self.onlyUncaughtCheck.setObjectName("onlyUncaughtCheck")
self.gridLayout_2.addWidget(self.onlyUncaughtCheck, 0, 4, 1, 1)
self.exceptionStackList = QtWidgets.QListWidget(self.exceptionGroup)
self.exceptionStackList.setAlternatingRowColors(True)
self.exceptionStackList.setObjectName("exceptionStackList")
self.gridLayout_2.addWidget(self.exceptionStackList, 2, 0, 1, 7)
self.runSelectedFrameCheck = QtWidgets.QCheckBox(self.exceptionGroup)
self.runSelectedFrameCheck.setChecked(True)
self.runSelectedFrameCheck.setObjectName("runSelectedFrameCheck")
self.gridLayout_2.addWidget(self.runSelectedFrameCheck, 3, 0, 1, 7)
self.exceptionInfoLabel = QtWidgets.QLabel(self.exceptionGroup)
self.exceptionInfoLabel.setWordWrap(True)
self.exceptionInfoLabel.setObjectName("exceptionInfoLabel")
self.gridLayout_2.addWidget(self.exceptionInfoLabel, 1, 0, 1, 7)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.gridLayout_2.addItem(spacerItem, 0, 5, 1, 1)
self.label = QtWidgets.QLabel(self.exceptionGroup)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 0, 2, 1, 1)
self.filterText = QtWidgets.QLineEdit(self.exceptionGroup)
self.filterText.setObjectName("filterText")
self.gridLayout_2.addWidget(self.filterText, 0, 3, 1, 1)
self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Console"))
self.historyBtn.setText(_translate("Form", "History.."))
self.exceptionBtn.setText(_translate("Form", "Exceptions.."))
self.exceptionGroup.setTitle(_translate("Form", "Exception Handling"))
self.clearExceptionBtn.setText(_translate("Form", "Clear Stack"))
self.catchAllExceptionsBtn.setText(_translate("Form", "Show All Exceptions"))
self.catchNextExceptionBtn.setText(_translate("Form", "Show Next Exception"))
self.onlyUncaughtCheck.setText(_translate("Form", "Only Uncaught Exceptions"))
self.runSelectedFrameCheck.setText(_translate("Form", "Run commands in selected stack frame"))
self.exceptionInfoLabel.setText(_translate("Form", "Stack Trace"))
self.label.setText(_translate("Form", "Filter (regex):"))
from .CmdInput import CmdInput

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..Qt import QtCore, QtGui from ..Qt import QtCore, QtGui, QtWidgets
import weakref import weakref
class Container(object): class Container(object):
@ -76,7 +76,11 @@ class Container(object):
self.area.topContainer = None self.area.topContainer = None
self.containerChanged(None) self.containerChanged(None)
def childEvent(self, ev): def childEvent_(self, ev):
# NOTE: this method has been renamed to avoid having the same method name as
# QSplitter.childEvent()
# this causes problems for PyQt6 since SplitContainer inherits from
# Container and QSplitter.
ch = ev.child() ch = ev.child()
if ev.removed() and hasattr(ch, 'sigStretchChanged'): if ev.removed() and hasattr(ch, 'sigStretchChanged'):
#print "Child", ev.child(), "removed, updating", self #print "Child", ev.child(), "removed, updating", self
@ -133,8 +137,8 @@ class SplitContainer(Container, QtGui.QSplitter):
self.setStretchFactor(i, sizes[i]) self.setStretchFactor(i, sizes[i])
def childEvent(self, ev): def childEvent(self, ev):
QtGui.QSplitter.childEvent(self, ev) super().childEvent(ev) # call QSplitter.childEvent()
Container.childEvent(self, ev) Container.childEvent_(self, ev)
#def restretchChildren(self): #def restretchChildren(self):
#sizes = self.sizes() #sizes = self.sizes()
@ -204,6 +208,16 @@ class VContainer(SplitContainer):
self.setSizes([int(s*scale) for s in sizes]) self.setSizes([int(s*scale) for s in sizes])
class StackedWidget(QtWidgets.QStackedWidget):
def __init__(self, *, container):
super().__init__()
self.container = container
def childEvent(self, ev):
super().childEvent(ev)
self.container.childEvent_(ev)
class TContainer(Container, QtGui.QWidget): class TContainer(Container, QtGui.QWidget):
sigStretchChanged = QtCore.Signal() sigStretchChanged = QtCore.Signal()
def __init__(self, area): def __init__(self, area):
@ -221,9 +235,8 @@ class TContainer(Container, QtGui.QWidget):
self.hTabLayout.setContentsMargins(0,0,0,0) self.hTabLayout.setContentsMargins(0,0,0,0)
self.layout.addWidget(self.hTabBox, 0, 1) self.layout.addWidget(self.hTabBox, 0, 1)
self.stack = QtGui.QStackedWidget() self.stack = StackedWidget(container=self)
self.layout.addWidget(self.stack, 1, 1) self.layout.addWidget(self.stack, 1, 1)
self.stack.childEvent = self.stackChildEvent
self.setLayout(self.layout) self.setLayout(self.layout)
@ -276,8 +289,4 @@ class TContainer(Container, QtGui.QWidget):
y = max(y, wy) y = max(y, wy)
self.setStretch(x, y) self.setStretch(x, y)
def stackChildEvent(self, ev):
QtGui.QStackedWidget.childEvent(self.stack, ev)
Container.childEvent(self, ev)
from . import Dock from . import Dock

View File

@ -5,6 +5,7 @@ from .DockDrop import *
from ..widgets.VerticalLabel import VerticalLabel from ..widgets.VerticalLabel import VerticalLabel
from ..python2_3 import asUnicode from ..python2_3 import asUnicode
class Dock(QtGui.QWidget, DockDrop): class Dock(QtGui.QWidget, DockDrop):
sigStretchChanged = QtCore.Signal() sigStretchChanged = QtCore.Signal()
@ -328,13 +329,13 @@ class DockLabel(VerticalLabel):
self.updateStyle() self.updateStyle()
def mousePressEvent(self, ev): def mousePressEvent(self, ev):
self.pressPos = ev.pos() self.pressPos = ev.localPos()
self.mouseMoved = False self.mouseMoved = False
ev.accept() ev.accept()
def mouseMoveEvent(self, ev): def mouseMoveEvent(self, ev):
if not self.mouseMoved: if not self.mouseMoved:
self.mouseMoved = (ev.pos() - self.pressPos).manhattanLength() > QtGui.QApplication.startDragDistance() self.mouseMoved = (ev.localPos() - self.pressPos).manhattanLength() > QtGui.QApplication.startDragDistance()
if self.mouseMoved and ev.buttons() == QtCore.Qt.LeftButton: if self.mouseMoved and ev.buttons() == QtCore.Qt.LeftButton:
self.dock.startDrag() self.dock.startDrag()

View File

@ -382,4 +382,4 @@ class TempAreaWindow(QtGui.QWidget):
dock.orig_area.addDock(dock, ) dock.orig_area.addDock(dock, )
# clear dock area, and close remaining docks # clear dock area, and close remaining docks
self.dockarea.clear() self.dockarea.clear()
QtGui.QWidget.closeEvent(self, *args) super().closeEvent(*args)

View File

@ -30,9 +30,9 @@ class DockDrop(object):
def dragMoveEvent(self, ev): def dragMoveEvent(self, ev):
#print "drag move" #print "drag move"
ld = ev.pos().x() ld = ev.posF().x()
rd = self.width() - ld rd = self.width() - ld
td = ev.pos().y() td = ev.posF().y()
bd = self.height() - td bd = self.height() - td
mn = min(ld, rd, td, bd) mn = min(ld, rd, td, bd)

View File

@ -128,7 +128,8 @@ class Exporter(object):
while len(childs) > 0: while len(childs) > 0:
ch = childs.pop(0) ch = childs.pop(0)
tree = self.getPaintItems(ch) tree = self.getPaintItems(ch)
if int(ch.flags() & ch.ItemStacksBehindParent) > 0 or (ch.zValue() < 0 and int(ch.flags() & ch.ItemNegativeZStacksBehindParent) > 0): if (ch.flags() & ch.ItemStacksBehindParent) or \
(ch.zValue() < 0 and (ch.flags() & ch.ItemNegativeZStacksBehindParent)):
preItems.extend(tree) preItems.extend(tree)
else: else:
postItems.extend(tree) postItems.extend(tree)

View File

@ -251,7 +251,7 @@ def _generateItemSvg(item, nodes=None, root=None, options={}):
childGroup = g1 ## add children directly to this node unless we are clipping childGroup = g1 ## add children directly to this node unless we are clipping
if not isinstance(item, QtGui.QGraphicsScene): if not isinstance(item, QtGui.QGraphicsScene):
## See if this item clips its children ## See if this item clips its children
if int(item.flags() & item.ItemClipsChildrenToShape) > 0: if item.flags() & item.ItemClipsChildrenToShape:
## Generate svg for just the path ## Generate svg for just the path
path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape()))
item.scene().addItem(path) item.scene().addItem(path)
@ -377,11 +377,11 @@ def correctCoordinates(node, defs, item, options):
families = ch.getAttribute('font-family').split(',') families = ch.getAttribute('font-family').split(',')
if len(families) == 1: if len(families) == 1:
font = QtGui.QFont(families[0].strip('" ')) font = QtGui.QFont(families[0].strip('" '))
if font.style() == font.SansSerif: if font.styleHint() == font.StyleHint.SansSerif:
families.append('sans-serif') families.append('sans-serif')
elif font.style() == font.Serif: elif font.styleHint() == font.StyleHint.Serif:
families.append('serif') families.append('serif')
elif font.style() == font.Courier: elif font.styleHint() == font.StyleHint.Courier:
families.append('monospace') families.append('monospace')
ch.setAttribute('font-family', ', '.join([f if ' ' not in f else '"%s"'%f for f in families])) ch.setAttribute('font-family', ', '.join([f if ' ' not in f else '"%s"'%f for f in families]))
@ -414,7 +414,7 @@ def itemTransform(item, root):
return tr return tr
if int(item.flags() & item.ItemIgnoresTransformations) > 0: if item.flags() & item.ItemIgnoresTransformations:
pos = item.pos() pos = item.pos()
parent = item.parentItem() parent = item.parentItem()
if parent is not None: if parent is not None:
@ -431,7 +431,7 @@ def itemTransform(item, root):
if nextRoot is None: if nextRoot is None:
nextRoot = root nextRoot = root
break break
if nextRoot is root or int(nextRoot.flags() & nextRoot.ItemIgnoresTransformations) > 0: if nextRoot is root or (nextRoot.flags() & nextRoot.ItemIgnoresTransformations):
break break
if isinstance(nextRoot, QtGui.QGraphicsScene): if isinstance(nextRoot, QtGui.QGraphicsScene):

View File

@ -7,7 +7,7 @@ pytest.importorskip("matplotlib")
app = pg.mkQApp() app = pg.mkQApp()
skip_qt6 = pytest.mark.skipif( skip_qt6 = pytest.mark.skipif(
pg.QT_LIB == "PySide6", pg.QT_LIB in ["PySide6", "PyQt6"],
reason= ( reason= (
"Matplotlib has no Qt6 support yet, " "Matplotlib has no Qt6 support yet, "
"see https://github.com/matplotlib/matplotlib/pull/19255" "see https://github.com/matplotlib/matplotlib/pull/19255"

View File

@ -0,0 +1,65 @@
# Form implementation generated from reading ui file 'pyqtgraph\flowchart\FlowchartCtrlTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(217, 499)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setVerticalSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.loadBtn = QtWidgets.QPushButton(Form)
self.loadBtn.setObjectName("loadBtn")
self.gridLayout.addWidget(self.loadBtn, 1, 0, 1, 1)
self.saveBtn = FeedbackButton(Form)
self.saveBtn.setObjectName("saveBtn")
self.gridLayout.addWidget(self.saveBtn, 1, 1, 1, 2)
self.saveAsBtn = FeedbackButton(Form)
self.saveAsBtn.setObjectName("saveAsBtn")
self.gridLayout.addWidget(self.saveAsBtn, 1, 3, 1, 1)
self.reloadBtn = FeedbackButton(Form)
self.reloadBtn.setCheckable(False)
self.reloadBtn.setFlat(False)
self.reloadBtn.setObjectName("reloadBtn")
self.gridLayout.addWidget(self.reloadBtn, 4, 0, 1, 2)
self.showChartBtn = QtWidgets.QPushButton(Form)
self.showChartBtn.setCheckable(True)
self.showChartBtn.setObjectName("showChartBtn")
self.gridLayout.addWidget(self.showChartBtn, 4, 2, 1, 2)
self.ctrlList = TreeWidget(Form)
self.ctrlList.setObjectName("ctrlList")
self.ctrlList.headerItem().setText(0, "1")
self.ctrlList.header().setVisible(False)
self.ctrlList.header().setStretchLastSection(False)
self.gridLayout.addWidget(self.ctrlList, 3, 0, 1, 4)
self.fileNameLabel = QtWidgets.QLabel(Form)
font = QtGui.QFont()
font.setBold(True)
self.fileNameLabel.setFont(font)
self.fileNameLabel.setText("")
self.fileNameLabel.setAlignment(QtCore.Qt.Alignment.AlignCenter)
self.fileNameLabel.setObjectName("fileNameLabel")
self.gridLayout.addWidget(self.fileNameLabel, 0, 1, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.loadBtn.setText(_translate("Form", "Load.."))
self.saveBtn.setText(_translate("Form", "Save"))
self.saveAsBtn.setText(_translate("Form", "As.."))
self.reloadBtn.setText(_translate("Form", "Reload Libs"))
self.showChartBtn.setText(_translate("Form", "Flowchart"))
from ..widgets.FeedbackButton import FeedbackButton
from ..widgets.TreeWidget import TreeWidget

View File

@ -0,0 +1,53 @@
# Form implementation generated from reading ui file 'pyqtgraph\flowchart\FlowchartTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(529, 329)
self.selInfoWidget = QtWidgets.QWidget(Form)
self.selInfoWidget.setGeometry(QtCore.QRect(260, 10, 264, 222))
self.selInfoWidget.setObjectName("selInfoWidget")
self.gridLayout = QtWidgets.QGridLayout(self.selInfoWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.selDescLabel = QtWidgets.QLabel(self.selInfoWidget)
self.selDescLabel.setText("")
self.selDescLabel.setAlignment(QtCore.Qt.Alignment.AlignLeading|QtCore.Qt.Alignment.AlignLeft|QtCore.Qt.Alignment.AlignTop)
self.selDescLabel.setWordWrap(True)
self.selDescLabel.setObjectName("selDescLabel")
self.gridLayout.addWidget(self.selDescLabel, 0, 0, 1, 1)
self.selNameLabel = QtWidgets.QLabel(self.selInfoWidget)
font = QtGui.QFont()
font.setBold(True)
self.selNameLabel.setFont(font)
self.selNameLabel.setText("")
self.selNameLabel.setObjectName("selNameLabel")
self.gridLayout.addWidget(self.selNameLabel, 0, 1, 1, 1)
self.selectedTree = DataTreeWidget(self.selInfoWidget)
self.selectedTree.setObjectName("selectedTree")
self.selectedTree.headerItem().setText(0, "1")
self.gridLayout.addWidget(self.selectedTree, 1, 0, 1, 2)
self.hoverText = QtWidgets.QTextEdit(Form)
self.hoverText.setGeometry(QtCore.QRect(0, 240, 521, 81))
self.hoverText.setObjectName("hoverText")
self.view = FlowchartGraphicsView(Form)
self.view.setGeometry(QtCore.QRect(0, 0, 256, 192))
self.view.setObjectName("view")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
from ..flowchart.FlowchartGraphicsView import FlowchartGraphicsView
from ..widgets.DataTreeWidget import DataTreeWidget

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..Qt import QtCore, QtGui from ..Qt import QtCore, QtGui, QtWidgets
from ..graphicsItems.GraphicsObject import GraphicsObject from ..graphicsItems.GraphicsObject import GraphicsObject
from .. import functions as fn from .. import functions as fn
from .Terminal import * from .Terminal import *
@ -436,6 +436,24 @@ class Node(QtCore.QObject):
t.disconnectAll() t.disconnectAll()
class TextItem(QtWidgets.QGraphicsTextItem):
def __init__(self, text, parent, on_update):
super().__init__(text, parent)
self.on_update = on_update
def focusOutEvent(self, ev):
super().focusOutEvent(ev)
if self.on_update is not None:
self.on_update()
def keyPressEvent(self, ev):
if ev.key() == QtCore.Qt.Key_Enter or ev.key() == QtCore.Qt.Key_Return:
if self.on_update is not None:
self.on_update()
return
super().keyPressEvent(ev)
#class NodeGraphicsItem(QtGui.QGraphicsItem): #class NodeGraphicsItem(QtGui.QGraphicsItem):
class NodeGraphicsItem(GraphicsObject): class NodeGraphicsItem(GraphicsObject):
def __init__(self, node): def __init__(self, node):
@ -461,16 +479,13 @@ class NodeGraphicsItem(GraphicsObject):
self.setFlags(flags) self.setFlags(flags)
self.bounds = QtCore.QRectF(0, 0, 100, 100) self.bounds = QtCore.QRectF(0, 0, 100, 100)
self.nameItem = QtGui.QGraphicsTextItem(self.node.name(), self) self.nameItem = TextItem(self.node.name(), self, self.labelChanged)
self.nameItem.setDefaultTextColor(QtGui.QColor(50, 50, 50)) self.nameItem.setDefaultTextColor(QtGui.QColor(50, 50, 50))
self.nameItem.moveBy(self.bounds.width()/2. - self.nameItem.boundingRect().width()/2., 0) self.nameItem.moveBy(self.bounds.width()/2. - self.nameItem.boundingRect().width()/2., 0)
self.nameItem.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction) self.nameItem.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
self.updateTerminals() self.updateTerminals()
#self.setZValue(10) #self.setZValue(10)
self.nameItem.focusOutEvent = self.labelFocusOut
self.nameItem.keyPressEvent = self.labelKeyPress
self.menu = None self.menu = None
self.buildMenu() self.buildMenu()
@ -481,16 +496,6 @@ class NodeGraphicsItem(GraphicsObject):
#item.setZValue(z+1) #item.setZValue(z+1)
#GraphicsObject.setZValue(self, z) #GraphicsObject.setZValue(self, z)
def labelFocusOut(self, ev):
QtGui.QGraphicsTextItem.focusOutEvent(self.nameItem, ev)
self.labelChanged()
def labelKeyPress(self, ev):
if ev.key() == QtCore.Qt.Key_Enter or ev.key() == QtCore.Qt.Key_Return:
self.labelChanged()
else:
QtGui.QGraphicsTextItem.keyPressEvent(self.nameItem, ev)
def labelChanged(self): def labelChanged(self):
newName = str(self.nameItem.toPlainText()) newName = str(self.nameItem.toPlainText())
if newName != self.node.name(): if newName != self.node.name():
@ -574,7 +579,7 @@ class NodeGraphicsItem(GraphicsObject):
def mouseClickEvent(self, ev): def mouseClickEvent(self, ev):
#print "Node.mouseClickEvent called." #print "Node.mouseClickEvent called."
if int(ev.button()) == int(QtCore.Qt.LeftButton): if ev.button() == QtCore.Qt.LeftButton:
ev.accept() ev.accept()
#print " ev.button: left" #print " ev.button: left"
sel = self.isSelected() sel = self.isSelected()
@ -587,7 +592,7 @@ class NodeGraphicsItem(GraphicsObject):
self.update() self.update()
#return ret #return ret
elif int(ev.button()) == int(QtCore.Qt.RightButton): elif ev.button() == QtCore.Qt.RightButton:
#print " ev.button: right" #print " ev.button: right"
ev.accept() ev.accept()
#pos = ev.screenPos() #pos = ev.screenPos()

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..Qt import QtCore, QtGui from ..Qt import QtCore, QtGui, QtWidgets
import weakref import weakref
from ..graphicsItems.GraphicsObject import GraphicsObject from ..graphicsItems.GraphicsObject import GraphicsObject
from .. import functions as fn from .. import functions as fn
@ -273,6 +273,25 @@ class Terminal(object):
""" """
return self._name < other._name return self._name < other._name
class TextItem(QtWidgets.QGraphicsTextItem):
def __init__(self, text, parent, on_update):
super().__init__(text, parent)
self.on_update = on_update
def focusOutEvent(self, ev):
super().focusOutEvent(ev)
if self.on_update is not None:
self.on_update()
def keyPressEvent(self, ev):
if ev.key() == QtCore.Qt.Key_Enter or ev.key() == QtCore.Qt.Key_Return:
if self.on_update is not None:
self.on_update()
return
super().keyPressEvent(ev)
class TerminalGraphicsItem(GraphicsObject): class TerminalGraphicsItem(GraphicsObject):
def __init__(self, term, parent=None): def __init__(self, term, parent=None):
@ -280,27 +299,16 @@ class TerminalGraphicsItem(GraphicsObject):
GraphicsObject.__init__(self, parent) GraphicsObject.__init__(self, parent)
self.brush = fn.mkBrush(0,0,0) self.brush = fn.mkBrush(0,0,0)
self.box = QtGui.QGraphicsRectItem(0, 0, 10, 10, self) self.box = QtGui.QGraphicsRectItem(0, 0, 10, 10, self)
self.label = QtGui.QGraphicsTextItem(self.term.name(), self) on_update = self.labelChanged if self.term.isRenamable() else None
self.label = TextItem(self.term.name(), self, on_update)
self.label.scale(0.7, 0.7) self.label.scale(0.7, 0.7)
self.newConnection = None self.newConnection = None
self.setFiltersChildEvents(True) ## to pick up mouse events on the rectitem self.setFiltersChildEvents(True) ## to pick up mouse events on the rectitem
if self.term.isRenamable(): if self.term.isRenamable():
self.label.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction) self.label.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
self.label.focusOutEvent = self.labelFocusOut
self.label.keyPressEvent = self.labelKeyPress
self.setZValue(1) self.setZValue(1)
self.menu = None self.menu = None
def labelFocusOut(self, ev):
QtGui.QGraphicsTextItem.focusOutEvent(self.label, ev)
self.labelChanged()
def labelKeyPress(self, ev):
if ev.key() == QtCore.Qt.Key_Enter or ev.key() == QtCore.Qt.Key_Return:
self.labelChanged()
else:
QtGui.QGraphicsTextItem.keyPressEvent(self.label, ev)
def labelChanged(self): def labelChanged(self):
newName = str(self.label.toPlainText()) newName = str(self.label.toPlainText())
if newName != self.term.name(): if newName != self.term.name():

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..Node import Node from ..Node import Node
from ...Qt import QtGui, QtCore from ...Qt import QtGui, QtCore, QtWidgets
import numpy as np import numpy as np
import sys import sys
from .common import * from .common import *
@ -173,6 +173,20 @@ class RegionSelectNode(CtrlNode):
self.update() self.update()
class TextEdit(QtWidgets.QTextEdit):
def __init__(self, on_update):
super().__init__()
self.on_update = on_update
self.lastText = None
def focusOutEvent(self, ev):
text = str(self.toPlainText())
if text != self.lastText:
self.lastText = text
self.on_update()
super().focusOutEvent(ev)
class EvalNode(Node): class EvalNode(Node):
"""Return the output of a string evaluated/executed by the python interpreter. """Return the output of a string evaluated/executed by the python interpreter.
The string may be either an expression or a python script, and inputs are accessed as the name of the terminal. The string may be either an expression or a python script, and inputs are accessed as the name of the terminal.
@ -190,15 +204,12 @@ class EvalNode(Node):
self.ui = QtGui.QWidget() self.ui = QtGui.QWidget()
self.layout = QtGui.QGridLayout() self.layout = QtGui.QGridLayout()
self.text = QtGui.QTextEdit() self.text = TextEdit(self.update)
self.text.setTabStopWidth(30) self.text.setTabStopWidth(30)
self.text.setPlainText("# Access inputs as args['input_name']\nreturn {'output': None} ## one key per output terminal") self.text.setPlainText("# Access inputs as args['input_name']\nreturn {'output': None} ## one key per output terminal")
self.layout.addWidget(self.text, 1, 0, 1, 2) self.layout.addWidget(self.text, 1, 0, 1, 2)
self.ui.setLayout(self.layout) self.ui.setLayout(self.layout)
self.text.focusOutEvent = self.focusOutEvent
self.lastText = None
def ctrlWidget(self): def ctrlWidget(self):
return self.ui return self.ui
@ -221,13 +232,6 @@ class EvalNode(Node):
def code(self): def code(self):
return self.text.toPlainText() return self.text.toPlainText()
def focusOutEvent(self, ev):
text = str(self.text.toPlainText())
if text != self.lastText:
self.lastText = text
self.update()
return QtGui.QTextEdit.focusOutEvent(self.text, ev)
def process(self, display=True, **args): def process(self, display=True, **args):
l = locals() l = locals()
l.update(args) l.update(args)

View File

@ -19,6 +19,7 @@ from pyqtgraph.util.cupy_helper import getCupy
from . import debug, reload from . import debug, reload
from .Qt import QtGui, QtCore, QT_LIB, QtVersion from .Qt import QtGui, QtCore, QT_LIB, QtVersion
from . import Qt
from .metaarray import MetaArray from .metaarray import MetaArray
from .pgcollections import OrderedDict from .pgcollections import OrderedDict
from .python2_3 import asUnicode, basestring from .python2_3 import asUnicode, basestring
@ -1254,23 +1255,28 @@ def makeQImage(imgData, alpha=None, copy=True, transpose=True):
imgData = imgData.copy() imgData = imgData.copy()
profile("copy") profile("copy")
if QT_LIB == 'PySide':
ch = ctypes.c_char.from_buffer(imgData, 0) # C++ QImage has two kind of constructors
img = QtGui.QImage(ch, imgData.shape[1], imgData.shape[0], imgFormat) # - QImage(const uchar*, ...)
elif QT_LIB in ['PySide2', 'PySide6']: # - QImage(uchar*, ...)
img = QtGui.QImage(imgData, imgData.shape[1], imgData.shape[0], imgFormat) # If the const constructor is used, subsequently calling any non-const method
# will trigger the COW mechanism, i.e. a copy is made under the hood.
if QT_LIB == 'PyQt5':
# PyQt5 -> non-const constructor
img_ptr = imgData.ctypes.data
elif QT_LIB == 'PyQt6':
# PyQt5 -> const constructor
# PyQt6 -> non-const constructor
img_ptr = Qt.sip.voidptr(imgData)
else: else:
## PyQt API for QImage changed between 4.9.3 and 4.9.6 (I don't know exactly which version it was) # bindings that support ndarray
## So we first attempt the 4.9.6 API, then fall back to 4.9.3 # PyQt5 -> const constructor
try: # PySide2 -> non-const constructor
img = QtGui.QImage(imgData.ctypes.data, imgData.shape[1], imgData.shape[0], imgFormat) # PySide6 -> non-const constructor
except: img_ptr = imgData
if copy:
# does not leak memory, is not mutable img = QtGui.QImage(img_ptr, imgData.shape[1], imgData.shape[0], imgFormat)
img = QtGui.QImage(buffer(imgData), imgData.shape[1], imgData.shape[0], imgFormat)
else:
# mutable, but leaks memory
img = QtGui.QImage(memoryview(imgData), imgData.shape[1], imgData.shape[0], imgFormat)
img.data = imgData img.data = imgData
return img return img
@ -1287,12 +1293,16 @@ def imageToArray(img, copy=False, transpose=True):
if QT_LIB in ['PySide', 'PySide2', 'PySide6']: if QT_LIB in ['PySide', 'PySide2', 'PySide6']:
arr = np.frombuffer(ptr, dtype=np.ubyte) arr = np.frombuffer(ptr, dtype=np.ubyte)
else: else:
ptr.setsize(img.byteCount()) try:
# removed in Qt6
nbytes = img.byteCount()
except AttributeError:
# introduced in Qt 5.10
# however Python 3.7 + PyQt5-5.12 in the CI fails with
# "TypeError: QImage.sizeInBytes() is a private method"
nbytes = img.sizeInBytes()
ptr.setsize(nbytes)
arr = np.asarray(ptr) arr = np.asarray(ptr)
if img.byteCount() != arr.size * arr.itemsize:
# Required for Python 2.6, PyQt 4.10
# If this works on all platforms, then there is no need to use np.asarray..
arr = np.frombuffer(ptr, np.ubyte, img.byteCount())
arr = arr.reshape(img.height(), img.width(), 4) arr = arr.reshape(img.height(), img.width(), 4)
if fmt == img.Format_RGB32: if fmt == img.Format_RGB32:
@ -1546,6 +1556,9 @@ def arrayToQPath(x, y, connect='all'):
buf = QtCore.QByteArray.fromRawData(path.strn) buf = QtCore.QByteArray.fromRawData(path.strn)
except TypeError: except TypeError:
buf = QtCore.QByteArray(bytes(path.strn)) buf = QtCore.QByteArray(bytes(path.strn))
except AttributeError:
# PyQt6 raises AttributeError
buf = QtCore.QByteArray(path.strn, path.strn.nbytes)
ds = QtCore.QDataStream(buf) ds = QtCore.QDataStream(buf)
ds >> path ds >> path

View File

@ -104,7 +104,7 @@ class ArrowItem(QtGui.QGraphicsPathItem):
def paint(self, p, *args): def paint(self, p, *args):
p.setRenderHint(QtGui.QPainter.Antialiasing) p.setRenderHint(QtGui.QPainter.Antialiasing)
QtGui.QGraphicsPathItem.paint(self, p, *args) super().paint(p, *args)
#p.setPen(fn.mkPen('r')) #p.setPen(fn.mkPen('r'))
#p.setBrush(fn.mkBrush(None)) #p.setBrush(fn.mkBrush(None))

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..Qt import QtGui, QtCore from ..Qt import QtGui, QtCore, QT_LIB
from ..python2_3 import asUnicode from ..python2_3 import asUnicode
import numpy as np import numpy as np
from ..Point import Point from ..Point import Point
@ -1103,19 +1103,28 @@ class AxisItem(GraphicsWidget):
width = textRect.width() width = textRect.width()
#self.textHeight = height #self.textHeight = height
offset = max(0,self.style['tickLength']) + textOffset offset = max(0,self.style['tickLength']) + textOffset
if self.orientation == 'left': if self.orientation == 'left':
textFlags = QtCore.Qt.TextDontClip|QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter alignFlags = QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter
rect = QtCore.QRectF(tickStop-offset-width, x-(height/2), width, height) rect = QtCore.QRectF(tickStop-offset-width, x-(height/2), width, height)
elif self.orientation == 'right': elif self.orientation == 'right':
textFlags = QtCore.Qt.TextDontClip|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter alignFlags = QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter
rect = QtCore.QRectF(tickStop+offset, x-(height/2), width, height) rect = QtCore.QRectF(tickStop+offset, x-(height/2), width, height)
elif self.orientation == 'top': elif self.orientation == 'top':
textFlags = QtCore.Qt.TextDontClip|QtCore.Qt.AlignHCenter|QtCore.Qt.AlignBottom alignFlags = QtCore.Qt.AlignHCenter|QtCore.Qt.AlignBottom
rect = QtCore.QRectF(x-width/2., tickStop-offset-height, width, height) rect = QtCore.QRectF(x-width/2., tickStop-offset-height, width, height)
elif self.orientation == 'bottom': elif self.orientation == 'bottom':
textFlags = QtCore.Qt.TextDontClip|QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop alignFlags = QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop
rect = QtCore.QRectF(x-width/2., tickStop+offset, width, height) rect = QtCore.QRectF(x-width/2., tickStop+offset, width, height)
if QT_LIB == 'PyQt6':
# PyQt6 doesn't allow or-ing of different enum types
# so we need to take its value property
textFlags = alignFlags.value | QtCore.Qt.TextDontClip.value
else:
# for PyQt5, the following expression is not commutative!
textFlags = alignFlags | QtCore.Qt.TextDontClip
#p.setPen(self.pen()) #p.setPen(self.pen())
#p.drawText(rect, textFlags, vstr) #p.drawText(rect, textFlags, vstr)
textSpecs.append((rect, textFlags, vstr)) textSpecs.append((rect, textFlags, vstr))

View File

@ -626,10 +626,9 @@ class GradientEditorItem(TickSliderItem):
def getGradient(self): def getGradient(self):
"""Return a QLinearGradient object.""" """Return a QLinearGradient object."""
g = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(self.length,0)) g = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(self.length,0))
stops = []
if self.colorMode == 'rgb': if self.colorMode == 'rgb':
ticks = self.listTicks() ticks = self.listTicks()
stops = [(x, QtGui.QColor(t.color)) for t,x in ticks] g.setStops([(x, QtGui.QColor(t.color)) for t,x in ticks])
elif self.colorMode == 'hsv': ## HSV mode is approximated for display by interpolating 10 points between each stop elif self.colorMode == 'hsv': ## HSV mode is approximated for display by interpolating 10 points between each stop
ticks = self.listTicks() ticks = self.listTicks()
stops = [] stops = []
@ -642,12 +641,7 @@ class GradientEditorItem(TickSliderItem):
x = x1 + dx*j x = x1 + dx*j
stops.append((x, self.getColor(x))) stops.append((x, self.getColor(x)))
stops.append((x2, self.getColor(x2))) stops.append((x2, self.getColor(x2)))
if hasattr(g, 'setStops'):
g.setStops(stops) g.setStops(stops)
else:
# PySide6 has a missing setStops binding
for pos, col in stops:
g.setColorAt(pos, col)
return g return g
def getColor(self, x, toQColor=True): def getColor(self, x, toQColor=True):

View File

@ -1,9 +1,6 @@
from ..Qt import QtGui, QtCore, QT_LIB from ..Qt import QtGui, QtCore, QT_LIB
if QT_LIB in ['PyQt4', 'PyQt5']: if QT_LIB.startswith('PyQt'):
try: from ..Qt import sip
from PyQt5 import sip
except ImportError:
import sip
from .GraphicsItem import GraphicsItem from .GraphicsItem import GraphicsItem
__all__ = ['GraphicsObject'] __all__ = ['GraphicsObject']
@ -21,7 +18,7 @@ class GraphicsObject(GraphicsItem, QtGui.QGraphicsObject):
GraphicsItem.__init__(self) GraphicsItem.__init__(self)
def itemChange(self, change, value): def itemChange(self, change, value):
ret = QtGui.QGraphicsObject.itemChange(self, change, value) ret = super().itemChange(change, value)
if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]: if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]:
self.parentChanged() self.parentChanged()
try: try:

View File

@ -245,7 +245,7 @@ class LinearRegionItem(GraphicsObject):
self.sigRegionChangeFinished.emit(self) self.sigRegionChangeFinished.emit(self)
def mouseDragEvent(self, ev): def mouseDragEvent(self, ev):
if not self.movable or int(ev.button() & QtCore.Qt.LeftButton) == 0: if not self.movable or ev.button() != QtCore.Qt.LeftButton:
return return
ev.accept() ev.accept()

View File

@ -0,0 +1,178 @@
# Form implementation generated from reading ui file 'pyqtgraph\graphicsItems\PlotItem\plotConfigTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(481, 840)
self.averageGroup = QtWidgets.QGroupBox(Form)
self.averageGroup.setGeometry(QtCore.QRect(0, 640, 242, 182))
self.averageGroup.setCheckable(True)
self.averageGroup.setChecked(False)
self.averageGroup.setObjectName("averageGroup")
self.gridLayout_5 = QtWidgets.QGridLayout(self.averageGroup)
self.gridLayout_5.setContentsMargins(0, 0, 0, 0)
self.gridLayout_5.setSpacing(0)
self.gridLayout_5.setObjectName("gridLayout_5")
self.avgParamList = QtWidgets.QListWidget(self.averageGroup)
self.avgParamList.setObjectName("avgParamList")
self.gridLayout_5.addWidget(self.avgParamList, 0, 0, 1, 1)
self.decimateGroup = QtWidgets.QFrame(Form)
self.decimateGroup.setGeometry(QtCore.QRect(10, 140, 191, 171))
self.decimateGroup.setObjectName("decimateGroup")
self.gridLayout_4 = QtWidgets.QGridLayout(self.decimateGroup)
self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
self.gridLayout_4.setSpacing(0)
self.gridLayout_4.setObjectName("gridLayout_4")
self.clipToViewCheck = QtWidgets.QCheckBox(self.decimateGroup)
self.clipToViewCheck.setObjectName("clipToViewCheck")
self.gridLayout_4.addWidget(self.clipToViewCheck, 7, 0, 1, 3)
self.maxTracesCheck = QtWidgets.QCheckBox(self.decimateGroup)
self.maxTracesCheck.setObjectName("maxTracesCheck")
self.gridLayout_4.addWidget(self.maxTracesCheck, 8, 0, 1, 2)
self.downsampleCheck = QtWidgets.QCheckBox(self.decimateGroup)
self.downsampleCheck.setObjectName("downsampleCheck")
self.gridLayout_4.addWidget(self.downsampleCheck, 0, 0, 1, 3)
self.peakRadio = QtWidgets.QRadioButton(self.decimateGroup)
self.peakRadio.setChecked(True)
self.peakRadio.setObjectName("peakRadio")
self.gridLayout_4.addWidget(self.peakRadio, 6, 1, 1, 2)
self.maxTracesSpin = QtWidgets.QSpinBox(self.decimateGroup)
self.maxTracesSpin.setObjectName("maxTracesSpin")
self.gridLayout_4.addWidget(self.maxTracesSpin, 8, 2, 1, 1)
self.forgetTracesCheck = QtWidgets.QCheckBox(self.decimateGroup)
self.forgetTracesCheck.setObjectName("forgetTracesCheck")
self.gridLayout_4.addWidget(self.forgetTracesCheck, 9, 0, 1, 3)
self.meanRadio = QtWidgets.QRadioButton(self.decimateGroup)
self.meanRadio.setObjectName("meanRadio")
self.gridLayout_4.addWidget(self.meanRadio, 3, 1, 1, 2)
self.subsampleRadio = QtWidgets.QRadioButton(self.decimateGroup)
self.subsampleRadio.setObjectName("subsampleRadio")
self.gridLayout_4.addWidget(self.subsampleRadio, 2, 1, 1, 2)
self.autoDownsampleCheck = QtWidgets.QCheckBox(self.decimateGroup)
self.autoDownsampleCheck.setChecked(True)
self.autoDownsampleCheck.setObjectName("autoDownsampleCheck")
self.gridLayout_4.addWidget(self.autoDownsampleCheck, 1, 2, 1, 1)
spacerItem = QtWidgets.QSpacerItem(30, 20, QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Policy.Minimum)
self.gridLayout_4.addItem(spacerItem, 2, 0, 1, 1)
self.downsampleSpin = QtWidgets.QSpinBox(self.decimateGroup)
self.downsampleSpin.setMinimum(1)
self.downsampleSpin.setMaximum(100000)
self.downsampleSpin.setProperty("value", 1)
self.downsampleSpin.setObjectName("downsampleSpin")
self.gridLayout_4.addWidget(self.downsampleSpin, 1, 1, 1, 1)
self.transformGroup = QtWidgets.QFrame(Form)
self.transformGroup.setGeometry(QtCore.QRect(10, 10, 171, 101))
self.transformGroup.setObjectName("transformGroup")
self.gridLayout = QtWidgets.QGridLayout(self.transformGroup)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.logYCheck = QtWidgets.QCheckBox(self.transformGroup)
self.logYCheck.setObjectName("logYCheck")
self.gridLayout.addWidget(self.logYCheck, 2, 0, 1, 1)
self.logXCheck = QtWidgets.QCheckBox(self.transformGroup)
self.logXCheck.setObjectName("logXCheck")
self.gridLayout.addWidget(self.logXCheck, 1, 0, 1, 1)
self.fftCheck = QtWidgets.QCheckBox(self.transformGroup)
self.fftCheck.setObjectName("fftCheck")
self.gridLayout.addWidget(self.fftCheck, 0, 0, 1, 1)
self.derivativeCheck = QtWidgets.QCheckBox(self.transformGroup)
self.derivativeCheck.setObjectName("derivativeCheck")
self.gridLayout.addWidget(self.derivativeCheck, 3, 0, 1, 1)
self.phasemapCheck = QtWidgets.QCheckBox(self.transformGroup)
self.phasemapCheck.setObjectName("phasemapCheck")
self.gridLayout.addWidget(self.phasemapCheck, 4, 0, 1, 1)
self.pointsGroup = QtWidgets.QGroupBox(Form)
self.pointsGroup.setGeometry(QtCore.QRect(10, 550, 234, 58))
self.pointsGroup.setCheckable(True)
self.pointsGroup.setObjectName("pointsGroup")
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.pointsGroup)
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.autoPointsCheck = QtWidgets.QCheckBox(self.pointsGroup)
self.autoPointsCheck.setChecked(True)
self.autoPointsCheck.setObjectName("autoPointsCheck")
self.verticalLayout_5.addWidget(self.autoPointsCheck)
self.gridGroup = QtWidgets.QFrame(Form)
self.gridGroup.setGeometry(QtCore.QRect(10, 460, 221, 81))
self.gridGroup.setObjectName("gridGroup")
self.gridLayout_2 = QtWidgets.QGridLayout(self.gridGroup)
self.gridLayout_2.setObjectName("gridLayout_2")
self.xGridCheck = QtWidgets.QCheckBox(self.gridGroup)
self.xGridCheck.setObjectName("xGridCheck")
self.gridLayout_2.addWidget(self.xGridCheck, 0, 0, 1, 2)
self.yGridCheck = QtWidgets.QCheckBox(self.gridGroup)
self.yGridCheck.setObjectName("yGridCheck")
self.gridLayout_2.addWidget(self.yGridCheck, 1, 0, 1, 2)
self.gridAlphaSlider = QtWidgets.QSlider(self.gridGroup)
self.gridAlphaSlider.setMaximum(255)
self.gridAlphaSlider.setProperty("value", 128)
self.gridAlphaSlider.setOrientation(QtCore.Qt.Orientations.Horizontal)
self.gridAlphaSlider.setObjectName("gridAlphaSlider")
self.gridLayout_2.addWidget(self.gridAlphaSlider, 2, 1, 1, 1)
self.label = QtWidgets.QLabel(self.gridGroup)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1)
self.alphaGroup = QtWidgets.QGroupBox(Form)
self.alphaGroup.setGeometry(QtCore.QRect(10, 390, 234, 60))
self.alphaGroup.setCheckable(True)
self.alphaGroup.setObjectName("alphaGroup")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.alphaGroup)
self.horizontalLayout.setObjectName("horizontalLayout")
self.autoAlphaCheck = QtWidgets.QCheckBox(self.alphaGroup)
self.autoAlphaCheck.setChecked(False)
self.autoAlphaCheck.setObjectName("autoAlphaCheck")
self.horizontalLayout.addWidget(self.autoAlphaCheck)
self.alphaSlider = QtWidgets.QSlider(self.alphaGroup)
self.alphaSlider.setMaximum(1000)
self.alphaSlider.setProperty("value", 1000)
self.alphaSlider.setOrientation(QtCore.Qt.Orientations.Horizontal)
self.alphaSlider.setObjectName("alphaSlider")
self.horizontalLayout.addWidget(self.alphaSlider)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.averageGroup.setToolTip(_translate("Form", "Display averages of the curves displayed in this plot. The parameter list allows you to choose parameters to average over (if any are available)."))
self.averageGroup.setTitle(_translate("Form", "Average"))
self.clipToViewCheck.setToolTip(_translate("Form", "Plot only the portion of each curve that is visible. This assumes X values are uniformly spaced."))
self.clipToViewCheck.setText(_translate("Form", "Clip to View"))
self.maxTracesCheck.setToolTip(_translate("Form", "If multiple curves are displayed in this plot, check this box to limit the number of traces that are displayed."))
self.maxTracesCheck.setText(_translate("Form", "Max Traces:"))
self.downsampleCheck.setText(_translate("Form", "Downsample"))
self.peakRadio.setToolTip(_translate("Form", "Downsample by drawing a saw wave that follows the min and max of the original data. This method produces the best visual representation of the data but is slower."))
self.peakRadio.setText(_translate("Form", "Peak"))
self.maxTracesSpin.setToolTip(_translate("Form", "If multiple curves are displayed in this plot, check \"Max Traces\" and set this value to limit the number of traces that are displayed."))
self.forgetTracesCheck.setToolTip(_translate("Form", "If MaxTraces is checked, remove curves from memory after they are hidden (saves memory, but traces can not be un-hidden)."))
self.forgetTracesCheck.setText(_translate("Form", "Forget hidden traces"))
self.meanRadio.setToolTip(_translate("Form", "Downsample by taking the mean of N samples."))
self.meanRadio.setText(_translate("Form", "Mean"))
self.subsampleRadio.setToolTip(_translate("Form", "Downsample by taking the first of N samples. This method is fastest and least accurate."))
self.subsampleRadio.setText(_translate("Form", "Subsample"))
self.autoDownsampleCheck.setToolTip(_translate("Form", "Automatically downsample data based on the visible range. This assumes X values are uniformly spaced."))
self.autoDownsampleCheck.setText(_translate("Form", "Auto"))
self.downsampleSpin.setToolTip(_translate("Form", "Downsample data before plotting. (plot every Nth sample)"))
self.downsampleSpin.setSuffix(_translate("Form", "x"))
self.logYCheck.setText(_translate("Form", "Log Y"))
self.logXCheck.setText(_translate("Form", "Log X"))
self.fftCheck.setText(_translate("Form", "Power Spectrum (FFT)"))
self.derivativeCheck.setText(_translate("Form", "dy/dx"))
self.phasemapCheck.setText(_translate("Form", "Y vs. Y\'"))
self.pointsGroup.setTitle(_translate("Form", "Points"))
self.autoPointsCheck.setText(_translate("Form", "Auto"))
self.xGridCheck.setText(_translate("Form", "Show X Grid"))
self.yGridCheck.setText(_translate("Form", "Show Y Grid"))
self.label.setText(_translate("Form", "Opacity"))
self.alphaGroup.setTitle(_translate("Form", "Alpha"))
self.autoAlphaCheck.setText(_translate("Form", "Auto"))

View File

@ -722,7 +722,7 @@ class ROI(GraphicsObject):
hover=True hover=True
for btn in [QtCore.Qt.LeftButton, QtCore.Qt.RightButton, QtCore.Qt.MiddleButton]: for btn in [QtCore.Qt.LeftButton, QtCore.Qt.RightButton, QtCore.Qt.MiddleButton]:
if int(self.acceptedMouseButtons() & btn) > 0 and ev.acceptClicks(btn): if (self.acceptedMouseButtons() & btn) and ev.acceptClicks(btn):
hover=True hover=True
if self.contextMenuEnabled(): if self.contextMenuEnabled():
ev.acceptClicks(QtCore.Qt.RightButton) ev.acceptClicks(QtCore.Qt.RightButton)
@ -794,7 +794,7 @@ class ROI(GraphicsObject):
if ev.button() == QtCore.Qt.RightButton and self.contextMenuEnabled(): if ev.button() == QtCore.Qt.RightButton and self.contextMenuEnabled():
self.raiseContextMenu(ev) self.raiseContextMenu(ev)
ev.accept() ev.accept()
elif int(ev.button() & self.acceptedMouseButtons()) > 0: elif ev.button() & self.acceptedMouseButtons():
ev.accept() ev.accept()
self.sigClicked.emit(self, ev) self.sigClicked.emit(self, ev)
else: else:
@ -820,7 +820,7 @@ class ROI(GraphicsObject):
""" """
return True return True
def movePoint(self, handle, pos, modifiers=QtCore.Qt.KeyboardModifier(), finish=True, coords='parent'): def movePoint(self, handle, pos, modifiers=QtCore.Qt.KeyboardModifiers(0), finish=True, coords='parent'):
## called by Handles when they are moved. ## called by Handles when they are moved.
## pos is the new position of the handle in scene coords, as requested by the handle. ## pos is the new position of the handle in scene coords, as requested by the handle.
@ -1343,7 +1343,7 @@ class Handle(UIGraphicsItem):
if ev.acceptDrags(QtCore.Qt.LeftButton): if ev.acceptDrags(QtCore.Qt.LeftButton):
hover=True hover=True
for btn in [QtCore.Qt.LeftButton, QtCore.Qt.RightButton, QtCore.Qt.MiddleButton]: for btn in [QtCore.Qt.LeftButton, QtCore.Qt.RightButton, QtCore.Qt.MiddleButton]:
if int(self.acceptedMouseButtons() & btn) > 0 and ev.acceptClicks(btn): if (self.acceptedMouseButtons() & btn) and ev.acceptClicks(btn):
hover=True hover=True
if hover: if hover:
@ -1358,7 +1358,7 @@ class Handle(UIGraphicsItem):
self.isMoving = False ## prevents any further motion self.isMoving = False ## prevents any further motion
self.movePoint(self.startPos, finish=True) self.movePoint(self.startPos, finish=True)
ev.accept() ev.accept()
elif int(ev.button() & self.acceptedMouseButtons()) > 0: elif ev.button() & self.acceptedMouseButtons():
ev.accept() ev.accept()
if ev.button() == QtCore.Qt.RightButton and self.deletable: if ev.button() == QtCore.Qt.RightButton and self.deletable:
self.raiseContextMenu(ev) self.raiseContextMenu(ev)
@ -1415,7 +1415,7 @@ class Handle(UIGraphicsItem):
self.currentPen = self.hoverPen self.currentPen = self.hoverPen
self.movePoint(pos, ev.modifiers(), finish=False) self.movePoint(pos, ev.modifiers(), finish=False)
def movePoint(self, pos, modifiers=QtCore.Qt.KeyboardModifier(), finish=True): def movePoint(self, pos, modifiers=QtCore.Qt.KeyboardModifiers(0), finish=True):
for r in self.rois: for r in self.rois:
if not r.checkPointMove(self, pos, modifiers): if not r.checkPointMove(self, pos, modifiers):
return return

View File

@ -1,11 +1,8 @@
from ..Qt import QtGui, QtCore, QT_LIB from ..Qt import QtGui, QtCore, QT_LIB
import weakref import weakref
from .GraphicsObject import GraphicsObject from .GraphicsObject import GraphicsObject
if QT_LIB in ['PyQt4', 'PyQt5']: if QT_LIB.startswith('PyQt'):
try: from ..Qt import sip
from PyQt5 import sip
except ImportError:
import sip
__all__ = ['UIGraphicsItem'] __all__ = ['UIGraphicsItem']
class UIGraphicsItem(GraphicsObject): class UIGraphicsItem(GraphicsObject):

View File

@ -1397,7 +1397,7 @@ class ViewBox(GraphicsWidget):
itemBounds.append((bounds, useX, useY, pxPad)) itemBounds.append((bounds, useX, useY, pxPad))
else: else:
if int(item.flags() & item.ItemHasNoContents) > 0: if item.flags() & item.ItemHasNoContents:
continue continue
bounds = self.mapFromItemToView(item, item.boundingRect()).boundingRect() bounds = self.mapFromItemToView(item, item.boundingRect()).boundingRect()
itemBounds.append((bounds, True, True, 0)) itemBounds.append((bounds, True, True, 0))

View File

@ -0,0 +1,88 @@
# Form implementation generated from reading ui file 'pyqtgraph\graphicsItems\ViewBox\axisCtrlTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(186, 154)
Form.setMaximumSize(QtCore.QSize(200, 16777215))
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(Form)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 7, 0, 1, 2)
self.linkCombo = QtWidgets.QComboBox(Form)
self.linkCombo.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents)
self.linkCombo.setObjectName("linkCombo")
self.gridLayout.addWidget(self.linkCombo, 7, 2, 1, 2)
self.autoPercentSpin = QtWidgets.QSpinBox(Form)
self.autoPercentSpin.setEnabled(True)
self.autoPercentSpin.setMinimum(1)
self.autoPercentSpin.setMaximum(100)
self.autoPercentSpin.setSingleStep(1)
self.autoPercentSpin.setProperty("value", 100)
self.autoPercentSpin.setObjectName("autoPercentSpin")
self.gridLayout.addWidget(self.autoPercentSpin, 2, 2, 1, 2)
self.autoRadio = QtWidgets.QRadioButton(Form)
self.autoRadio.setChecked(True)
self.autoRadio.setObjectName("autoRadio")
self.gridLayout.addWidget(self.autoRadio, 2, 0, 1, 2)
self.manualRadio = QtWidgets.QRadioButton(Form)
self.manualRadio.setObjectName("manualRadio")
self.gridLayout.addWidget(self.manualRadio, 1, 0, 1, 2)
self.minText = QtWidgets.QLineEdit(Form)
self.minText.setObjectName("minText")
self.gridLayout.addWidget(self.minText, 1, 2, 1, 1)
self.maxText = QtWidgets.QLineEdit(Form)
self.maxText.setObjectName("maxText")
self.gridLayout.addWidget(self.maxText, 1, 3, 1, 1)
self.invertCheck = QtWidgets.QCheckBox(Form)
self.invertCheck.setObjectName("invertCheck")
self.gridLayout.addWidget(self.invertCheck, 5, 0, 1, 4)
self.mouseCheck = QtWidgets.QCheckBox(Form)
self.mouseCheck.setChecked(True)
self.mouseCheck.setObjectName("mouseCheck")
self.gridLayout.addWidget(self.mouseCheck, 6, 0, 1, 4)
self.visibleOnlyCheck = QtWidgets.QCheckBox(Form)
self.visibleOnlyCheck.setObjectName("visibleOnlyCheck")
self.gridLayout.addWidget(self.visibleOnlyCheck, 3, 2, 1, 2)
self.autoPanCheck = QtWidgets.QCheckBox(Form)
self.autoPanCheck.setObjectName("autoPanCheck")
self.gridLayout.addWidget(self.autoPanCheck, 4, 2, 1, 2)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.label.setText(_translate("Form", "Link Axis:"))
self.linkCombo.setToolTip(_translate("Form", "<html><head/><body><p>Links this axis with another view. When linked, both views will display the same data range.</p></body></html>"))
self.autoPercentSpin.setToolTip(_translate("Form", "<html><head/><body><p>Percent of data to be visible when auto-scaling. It may be useful to decrease this value for data with spiky noise.</p></body></html>"))
self.autoPercentSpin.setSuffix(_translate("Form", "%"))
self.autoRadio.setToolTip(_translate("Form", "<html><head/><body><p>Automatically resize this axis whenever the displayed data is changed.</p></body></html>"))
self.autoRadio.setText(_translate("Form", "Auto"))
self.manualRadio.setToolTip(_translate("Form", "<html><head/><body><p>Set the range for this axis manually. This disables automatic scaling. </p></body></html>"))
self.manualRadio.setText(_translate("Form", "Manual"))
self.minText.setToolTip(_translate("Form", "<html><head/><body><p>Minimum value to display for this axis.</p></body></html>"))
self.minText.setText(_translate("Form", "0"))
self.maxText.setToolTip(_translate("Form", "<html><head/><body><p>Maximum value to display for this axis.</p></body></html>"))
self.maxText.setText(_translate("Form", "0"))
self.invertCheck.setToolTip(_translate("Form", "<html><head/><body><p>Inverts the display of this axis. (+y points downward instead of upward)</p></body></html>"))
self.invertCheck.setText(_translate("Form", "Invert Axis"))
self.mouseCheck.setToolTip(_translate("Form", "<html><head/><body><p>Enables mouse interaction (panning, scaling) for this axis.</p></body></html>"))
self.mouseCheck.setText(_translate("Form", "Mouse Enabled"))
self.visibleOnlyCheck.setToolTip(_translate("Form", "<html><head/><body><p>When checked, the axis will only auto-scale to data that is visible along the orthogonal axis.</p></body></html>"))
self.visibleOnlyCheck.setText(_translate("Form", "Visible Data Only"))
self.autoPanCheck.setToolTip(_translate("Form", "<html><head/><body><p>When checked, the axis will automatically pan to center on the current data, but the scale along this axis will not change.</p></body></html>"))
self.autoPanCheck.setText(_translate("Form", "Auto Pan Only"))

View File

@ -63,8 +63,8 @@ def test_mouseInteraction():
plt.setYRange(-10, 10) plt.setYRange(-10, 10)
# test horizontal drag # test horizontal drag
pos = plt.plotItem.vb.mapViewToScene(pg.Point(0,5)).toPoint() pos = plt.plotItem.vb.mapViewToScene(pg.Point(0,5))
pos2 = pos - QtCore.QPoint(200, 200) pos2 = pos - QtCore.QPointF(200, 200)
mouseMove(plt, pos) mouseMove(plt, pos)
assert vline.mouseHovering is True and hline.mouseHovering is False assert vline.mouseHovering is True and hline.mouseHovering is False
mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton) mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton)
@ -72,17 +72,17 @@ def test_mouseInteraction():
assert abs(vline.value() - plt.plotItem.vb.mapSceneToView(pos2).x()) <= px assert abs(vline.value() - plt.plotItem.vb.mapSceneToView(pos2).x()) <= px
# test missed drag # test missed drag
pos = plt.plotItem.vb.mapViewToScene(pg.Point(5,0)).toPoint() pos = plt.plotItem.vb.mapViewToScene(pg.Point(5,0))
pos = pos + QtCore.QPoint(0, 6) pos = pos + QtCore.QPointF(0, 6)
pos2 = pos + QtCore.QPoint(-20, -20) pos2 = pos + QtCore.QPointF(-20, -20)
mouseMove(plt, pos) mouseMove(plt, pos)
assert vline.mouseHovering is False and hline.mouseHovering is False assert vline.mouseHovering is False and hline.mouseHovering is False
mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton) mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton)
assert hline.value() == 0 assert hline.value() == 0
# test vertical drag # test vertical drag
pos = plt.plotItem.vb.mapViewToScene(pg.Point(5,0)).toPoint() pos = plt.plotItem.vb.mapViewToScene(pg.Point(5,0))
pos2 = pos - QtCore.QPoint(50, 50) pos2 = pos - QtCore.QPointF(50, 50)
mouseMove(plt, pos) mouseMove(plt, pos)
assert vline.mouseHovering is False and hline.mouseHovering is True assert vline.mouseHovering is False and hline.mouseHovering is True
mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton) mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton)
@ -90,8 +90,8 @@ def test_mouseInteraction():
assert abs(hline.value() - plt.plotItem.vb.mapSceneToView(pos2).y()) <= px assert abs(hline.value() - plt.plotItem.vb.mapSceneToView(pos2).y()) <= px
# test non-interactive line # test non-interactive line
pos = plt.plotItem.vb.mapViewToScene(pg.Point(5,-1)).toPoint() pos = plt.plotItem.vb.mapViewToScene(pg.Point(5,-1))
pos2 = pos - QtCore.QPoint(50, 50) pos2 = pos - QtCore.QPointF(50, 50)
mouseMove(plt, pos) mouseMove(plt, pos)
assert hline2.mouseHovering == False assert hline2.mouseHovering == False
mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton) mouseDrag(plt, pos, pos2, QtCore.Qt.LeftButton)

View File

@ -450,7 +450,7 @@ class ImageView(QtGui.QWidget):
self.keysPressed[ev.key()] = 1 self.keysPressed[ev.key()] = 1
self.evalKeyState() self.evalKeyState()
else: else:
QtGui.QWidget.keyPressEvent(self, ev) super().keyPressEvent(ev)
def keyReleaseEvent(self, ev): def keyReleaseEvent(self, ev):
if ev.key() in [QtCore.Qt.Key_Space, QtCore.Qt.Key_Home, QtCore.Qt.Key_End]: if ev.key() in [QtCore.Qt.Key_Space, QtCore.Qt.Key_Home, QtCore.Qt.Key_End]:
@ -465,7 +465,7 @@ class ImageView(QtGui.QWidget):
self.keysPressed = {} self.keysPressed = {}
self.evalKeyState() self.evalKeyState()
else: else:
QtGui.QWidget.keyReleaseEvent(self, ev) super().keyReleaseEvent(ev)
def evalKeyState(self): def evalKeyState(self):
if len(self.keysPressed) == 1: if len(self.keysPressed) == 1:

View File

@ -0,0 +1,151 @@
# Form implementation generated from reading ui file 'pyqtgraph\imageview\ImageViewTemplate.ui'
#
# Created by: PyQt6 UI code generator 6.0.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(726, 588)
self.gridLayout_3 = QtWidgets.QGridLayout(Form)
self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
self.gridLayout_3.setSpacing(0)
self.gridLayout_3.setObjectName("gridLayout_3")
self.splitter = QtWidgets.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Orientations.Vertical)
self.splitter.setObjectName("splitter")
self.layoutWidget = QtWidgets.QWidget(self.splitter)
self.layoutWidget.setObjectName("layoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName("gridLayout")
self.graphicsView = GraphicsView(self.layoutWidget)
self.graphicsView.setObjectName("graphicsView")
self.gridLayout.addWidget(self.graphicsView, 0, 0, 2, 1)
self.histogram = HistogramLUTWidget(self.layoutWidget)
self.histogram.setObjectName("histogram")
self.gridLayout.addWidget(self.histogram, 0, 1, 1, 2)
self.roiBtn = QtWidgets.QPushButton(self.layoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.roiBtn.sizePolicy().hasHeightForWidth())
self.roiBtn.setSizePolicy(sizePolicy)
self.roiBtn.setCheckable(True)
self.roiBtn.setObjectName("roiBtn")
self.gridLayout.addWidget(self.roiBtn, 1, 1, 1, 1)
self.menuBtn = QtWidgets.QPushButton(self.layoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.menuBtn.sizePolicy().hasHeightForWidth())
self.menuBtn.setSizePolicy(sizePolicy)
self.menuBtn.setObjectName("menuBtn")
self.gridLayout.addWidget(self.menuBtn, 1, 2, 1, 1)
self.roiPlot = PlotWidget(self.splitter)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.roiPlot.sizePolicy().hasHeightForWidth())
self.roiPlot.setSizePolicy(sizePolicy)
self.roiPlot.setMinimumSize(QtCore.QSize(0, 40))
self.roiPlot.setObjectName("roiPlot")
self.gridLayout_3.addWidget(self.splitter, 0, 0, 1, 1)
self.normGroup = QtWidgets.QGroupBox(Form)
self.normGroup.setObjectName("normGroup")
self.gridLayout_2 = QtWidgets.QGridLayout(self.normGroup)
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
self.gridLayout_2.setSpacing(0)
self.gridLayout_2.setObjectName("gridLayout_2")
self.normSubtractRadio = QtWidgets.QRadioButton(self.normGroup)
self.normSubtractRadio.setObjectName("normSubtractRadio")
self.gridLayout_2.addWidget(self.normSubtractRadio, 0, 2, 1, 1)
self.normDivideRadio = QtWidgets.QRadioButton(self.normGroup)
self.normDivideRadio.setChecked(False)
self.normDivideRadio.setObjectName("normDivideRadio")
self.gridLayout_2.addWidget(self.normDivideRadio, 0, 1, 1, 1)
self.label_5 = QtWidgets.QLabel(self.normGroup)
font = QtGui.QFont()
font.setBold(True)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.gridLayout_2.addWidget(self.label_5, 0, 0, 1, 1)
self.label_3 = QtWidgets.QLabel(self.normGroup)
font = QtGui.QFont()
font.setBold(True)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.gridLayout_2.addWidget(self.label_3, 1, 0, 1, 1)
self.label_4 = QtWidgets.QLabel(self.normGroup)
font = QtGui.QFont()
font.setBold(True)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 2, 0, 1, 1)
self.normROICheck = QtWidgets.QCheckBox(self.normGroup)
self.normROICheck.setObjectName("normROICheck")
self.gridLayout_2.addWidget(self.normROICheck, 1, 1, 1, 1)
self.normXBlurSpin = QtWidgets.QDoubleSpinBox(self.normGroup)
self.normXBlurSpin.setObjectName("normXBlurSpin")
self.gridLayout_2.addWidget(self.normXBlurSpin, 2, 2, 1, 1)
self.label_8 = QtWidgets.QLabel(self.normGroup)
self.label_8.setAlignment(QtCore.Qt.Alignment.AlignRight|QtCore.Qt.Alignment.AlignTrailing|QtCore.Qt.Alignment.AlignVCenter)
self.label_8.setObjectName("label_8")
self.gridLayout_2.addWidget(self.label_8, 2, 1, 1, 1)
self.label_9 = QtWidgets.QLabel(self.normGroup)
self.label_9.setAlignment(QtCore.Qt.Alignment.AlignRight|QtCore.Qt.Alignment.AlignTrailing|QtCore.Qt.Alignment.AlignVCenter)
self.label_9.setObjectName("label_9")
self.gridLayout_2.addWidget(self.label_9, 2, 3, 1, 1)
self.normYBlurSpin = QtWidgets.QDoubleSpinBox(self.normGroup)
self.normYBlurSpin.setObjectName("normYBlurSpin")
self.gridLayout_2.addWidget(self.normYBlurSpin, 2, 4, 1, 1)
self.label_10 = QtWidgets.QLabel(self.normGroup)
self.label_10.setAlignment(QtCore.Qt.Alignment.AlignRight|QtCore.Qt.Alignment.AlignTrailing|QtCore.Qt.Alignment.AlignVCenter)
self.label_10.setObjectName("label_10")
self.gridLayout_2.addWidget(self.label_10, 2, 5, 1, 1)
self.normOffRadio = QtWidgets.QRadioButton(self.normGroup)
self.normOffRadio.setChecked(True)
self.normOffRadio.setObjectName("normOffRadio")
self.gridLayout_2.addWidget(self.normOffRadio, 0, 3, 1, 1)
self.normTimeRangeCheck = QtWidgets.QCheckBox(self.normGroup)
self.normTimeRangeCheck.setObjectName("normTimeRangeCheck")
self.gridLayout_2.addWidget(self.normTimeRangeCheck, 1, 3, 1, 1)
self.normFrameCheck = QtWidgets.QCheckBox(self.normGroup)
self.normFrameCheck.setObjectName("normFrameCheck")
self.gridLayout_2.addWidget(self.normFrameCheck, 1, 2, 1, 1)
self.normTBlurSpin = QtWidgets.QDoubleSpinBox(self.normGroup)
self.normTBlurSpin.setObjectName("normTBlurSpin")
self.gridLayout_2.addWidget(self.normTBlurSpin, 2, 6, 1, 1)
self.gridLayout_3.addWidget(self.normGroup, 1, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.roiBtn.setText(_translate("Form", "ROI"))
self.menuBtn.setText(_translate("Form", "Menu"))
self.normGroup.setTitle(_translate("Form", "Normalization"))
self.normSubtractRadio.setText(_translate("Form", "Subtract"))
self.normDivideRadio.setText(_translate("Form", "Divide"))
self.label_5.setText(_translate("Form", "Operation:"))
self.label_3.setText(_translate("Form", "Mean:"))
self.label_4.setText(_translate("Form", "Blur:"))
self.normROICheck.setText(_translate("Form", "ROI"))
self.label_8.setText(_translate("Form", "X"))
self.label_9.setText(_translate("Form", "Y"))
self.label_10.setText(_translate("Form", "T"))
self.normOffRadio.setText(_translate("Form", "Off"))
self.normTimeRangeCheck.setText(_translate("Form", "Time range"))
self.normFrameCheck.setText(_translate("Form", "Frame"))
from ..widgets.GraphicsView import GraphicsView
from ..widgets.HistogramLUTWidget import HistogramLUTWidget
from ..widgets.PlotWidget import PlotWidget

View File

@ -401,11 +401,12 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
return xDist / self.width() return xDist / self.width()
def mousePressEvent(self, ev): def mousePressEvent(self, ev):
self.mousePos = ev.pos() self.mousePos = ev.localPos()
def mouseMoveEvent(self, ev): def mouseMoveEvent(self, ev):
diff = ev.pos() - self.mousePos lpos = ev.localPos()
self.mousePos = ev.pos() diff = lpos - self.mousePos
self.mousePos = lpos
if ev.buttons() == QtCore.Qt.LeftButton: if ev.buttons() == QtCore.Qt.LeftButton:
if (ev.modifiers() & QtCore.Qt.ControlModifier): if (ev.modifiers() & QtCore.Qt.ControlModifier):

View File

@ -157,8 +157,8 @@ class ParameterTree(TreeWidget):
self.lastSel = sel[0] self.lastSel = sel[0]
if hasattr(sel[0], 'selected'): if hasattr(sel[0], 'selected'):
sel[0].selected(True) sel[0].selected(True)
return TreeWidget.selectionChanged(self, *args) return super().selectionChanged(*args)
def wheelEvent(self, ev): def wheelEvent(self, ev):
self.clearSelection() self.clearSelection()
return TreeWidget.wheelEvent(self, ev) return super().wheelEvent(ev)

View File

@ -257,7 +257,7 @@ def assertImageMatch(im1, im2, minCorr=None, pxThreshold=50.,
assert im1.dtype == im2.dtype assert im1.dtype == im2.dtype
if pxCount == -1: if pxCount == -1:
if QT_LIB in {'PyQt5', 'PySide2', 'PySide6'}: if QT_LIB in {'PyQt5', 'PySide2', 'PySide6', 'PyQt6'}:
# Qt5 generates slightly different results; relax the tolerance # Qt5 generates slightly different results; relax the tolerance
# until test images are updated. # until test images are updated.
pxCount = int(im1.shape[0] * im1.shape[1] * 0.01) pxCount = int(im1.shape[0] * im1.shape[1] * 0.01)

View File

@ -1,5 +1,5 @@
import time import time
from ..Qt import QtCore, QtGui, QtTest, QT_LIB from ..Qt import QtCore, QtGui, QtTest
def resizeWindow(win, w, h, timeout=2.0): def resizeWindow(win, w, h, timeout=2.0):
@ -32,8 +32,6 @@ def mousePress(widget, pos, button, modifier=None):
widget = widget.viewport() widget = widget.viewport()
if modifier is None: if modifier is None:
modifier = QtCore.Qt.NoModifier modifier = QtCore.Qt.NoModifier
if QT_LIB != 'PyQt5' and isinstance(pos, QtCore.QPointF):
pos = pos.toPoint()
event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, pos, button, QtCore.Qt.NoButton, modifier) event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, pos, button, QtCore.Qt.NoButton, modifier)
QtGui.QApplication.sendEvent(widget, event) QtGui.QApplication.sendEvent(widget, event)
@ -43,8 +41,6 @@ def mouseRelease(widget, pos, button, modifier=None):
widget = widget.viewport() widget = widget.viewport()
if modifier is None: if modifier is None:
modifier = QtCore.Qt.NoModifier modifier = QtCore.Qt.NoModifier
if QT_LIB != 'PyQt5' and isinstance(pos, QtCore.QPointF):
pos = pos.toPoint()
event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonRelease, pos, button, QtCore.Qt.NoButton, modifier) event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonRelease, pos, button, QtCore.Qt.NoButton, modifier)
QtGui.QApplication.sendEvent(widget, event) QtGui.QApplication.sendEvent(widget, event)
@ -56,8 +52,6 @@ def mouseMove(widget, pos, buttons=None, modifier=None):
modifier = QtCore.Qt.NoModifier modifier = QtCore.Qt.NoModifier
if buttons is None: if buttons is None:
buttons = QtCore.Qt.NoButton buttons = QtCore.Qt.NoButton
if QT_LIB != 'PyQt5' and isinstance(pos, QtCore.QPointF):
pos = pos.toPoint()
event = QtGui.QMouseEvent(QtCore.QEvent.MouseMove, pos, QtCore.Qt.NoButton, buttons, modifier) event = QtGui.QMouseEvent(QtCore.QEvent.MouseMove, pos, QtCore.Qt.NoButton, buttons, modifier)
QtGui.QApplication.sendEvent(widget, event) QtGui.QApplication.sendEvent(widget, event)

View File

@ -35,7 +35,7 @@ class ColorButton(QtGui.QPushButton):
self.setMinimumWidth(15) self.setMinimumWidth(15)
def paintEvent(self, ev): def paintEvent(self, ev):
QtGui.QPushButton.paintEvent(self, ev) super().paintEvent(ev)
p = QtGui.QPainter(self) p = QtGui.QPainter(self)
rect = self.rect().adjusted(6, 6, -6, -6) rect = self.rect().adjusted(6, 6, -6, -6)
## draw white base, then texture for indicating transparency, then actual color ## draw white base, then texture for indicating transparency, then actual color

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..Qt import QtGui, QtCore from ..Qt import QtGui, QtCore, QtWidgets, QT_LIB
from .GraphicsView import GraphicsView from .GraphicsView import GraphicsView
from ..graphicsItems.GradientEditorItem import GradientEditorItem from ..graphicsItems.GradientEditorItem import GradientEditorItem
import weakref import weakref
@ -40,7 +40,18 @@ class GradientWidget(GraphicsView):
self.setOrientation(orientation) self.setOrientation(orientation)
self.setCacheMode(self.CacheNone) self.setCacheMode(self.CacheNone)
self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing) self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)
self.setFrameStyle(QtGui.QFrame.NoFrame | QtGui.QFrame.Plain)
if QT_LIB == 'PyQt6':
# PyQt6 doesn't allow or-ing of different enum types
# so we need to take its value property
NoFrame = QtWidgets.QFrame.Shape.NoFrame.value
Plain = QtWidgets.QFrame.Shadow.Plain.value
else:
NoFrame = QtWidgets.QFrame.NoFrame
Plain = QtWidgets.QFrame.Plain
frame_style = NoFrame | Plain
self.setFrameStyle(frame_style)
#self.setBackgroundRole(QtGui.QPalette.NoRole) #self.setBackgroundRole(QtGui.QPalette.NoRole)
#self.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.NoBrush)) #self.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
#self.setAutoFillBackground(False) #self.setAutoFillBackground(False)

View File

@ -25,6 +25,7 @@ from .. import getConfigOption
__all__ = ['GraphicsView'] __all__ = ['GraphicsView']
class GraphicsView(QtGui.QGraphicsView): class GraphicsView(QtGui.QGraphicsView):
"""Re-implementation of QGraphicsView that removes scrollbars and allows unambiguous control of the """Re-implementation of QGraphicsView that removes scrollbars and allows unambiguous control of the
viewed coordinate range. Also automatically creates a GraphicsScene and a central QGraphicsWidget viewed coordinate range. Also automatically creates a GraphicsScene and a central QGraphicsWidget
@ -157,11 +158,11 @@ class GraphicsView(QtGui.QGraphicsView):
def paintEvent(self, ev): def paintEvent(self, ev):
self.scene().prepareForPaint() self.scene().prepareForPaint()
return QtGui.QGraphicsView.paintEvent(self, ev) return super().paintEvent(ev)
def render(self, *args, **kwds): def render(self, *args, **kwds):
self.scene().prepareForPaint() self.scene().prepareForPaint()
return QtGui.QGraphicsView.render(self, *args, **kwds) return super().render(*args, **kwds)
def close(self): def close(self):
@ -328,10 +329,9 @@ class GraphicsView(QtGui.QGraphicsView):
GraphicsView.setRange(self, r1, padding=[0, padding], propagate=False) GraphicsView.setRange(self, r1, padding=[0, padding], propagate=False)
def wheelEvent(self, ev): def wheelEvent(self, ev):
QtGui.QGraphicsView.wheelEvent(self, ev) super().wheelEvent(ev)
if not self.mouseEnabled: if not self.mouseEnabled:
return return
delta = 0 delta = 0
if QT_LIB in ['PyQt4', 'PySide']: if QT_LIB in ['PyQt4', 'PySide']:
delta = ev.delta() delta = ev.delta()
@ -352,20 +352,21 @@ class GraphicsView(QtGui.QGraphicsView):
self.scene().leaveEvent(ev) ## inform scene when mouse leaves self.scene().leaveEvent(ev) ## inform scene when mouse leaves
def mousePressEvent(self, ev): def mousePressEvent(self, ev):
QtGui.QGraphicsView.mousePressEvent(self, ev) super().mousePressEvent(ev)
if not self.mouseEnabled: if not self.mouseEnabled:
return return
self.lastMousePos = Point(ev.pos()) lpos = ev.localPos()
self.mousePressPos = ev.pos() self.lastMousePos = lpos
self.mousePressPos = lpos
self.clickAccepted = ev.isAccepted() self.clickAccepted = ev.isAccepted()
if not self.clickAccepted: if not self.clickAccepted:
self.scene().clearSelection() self.scene().clearSelection()
return ## Everything below disabled for now.. return ## Everything below disabled for now..
def mouseReleaseEvent(self, ev): def mouseReleaseEvent(self, ev):
QtGui.QGraphicsView.mouseReleaseEvent(self, ev) super().mouseReleaseEvent(ev)
if not self.mouseEnabled: if not self.mouseEnabled:
return return
self.sigMouseReleased.emit(ev) self.sigMouseReleased.emit(ev)
@ -373,15 +374,16 @@ class GraphicsView(QtGui.QGraphicsView):
return ## Everything below disabled for now.. return ## Everything below disabled for now..
def mouseMoveEvent(self, ev): def mouseMoveEvent(self, ev):
lpos = ev.localPos()
if self.lastMousePos is None: if self.lastMousePos is None:
self.lastMousePos = Point(ev.pos()) self.lastMousePos = lpos
delta = Point(ev.pos() - self.lastMousePos.toQPoint()) delta = Point(lpos - self.lastMousePos)
self.lastMousePos = Point(ev.pos()) self.lastMousePos = lpos
QtGui.QGraphicsView.mouseMoveEvent(self, ev) super().mouseMoveEvent(ev)
if not self.mouseEnabled: if not self.mouseEnabled:
return return
self.sigSceneMouseMoved.emit(self.mapToScene(ev.pos())) self.sigSceneMouseMoved.emit(self.mapToScene(lpos))
if self.clickAccepted: ## Ignore event if an item in the scene has already claimed it. if self.clickAccepted: ## Ignore event if an item in the scene has already claimed it.
return return

View File

@ -18,11 +18,11 @@ class JoystickButton(QtGui.QPushButton):
def mousePressEvent(self, ev): def mousePressEvent(self, ev):
self.setChecked(True) self.setChecked(True)
self.pressPos = ev.pos() self.pressPos = ev.localPos()
ev.accept() ev.accept()
def mouseMoveEvent(self, ev): def mouseMoveEvent(self, ev):
dif = ev.pos()-self.pressPos dif = ev.localPos()-self.pressPos
self.setState(dif.x(), -dif.y()) self.setState(dif.x(), -dif.y())
def mouseReleaseEvent(self, ev): def mouseReleaseEvent(self, ev):
@ -64,14 +64,14 @@ class JoystickButton(QtGui.QPushButton):
self.sigStateChanged.emit(self, self.state) self.sigStateChanged.emit(self, self.state)
def paintEvent(self, ev): def paintEvent(self, ev):
QtGui.QPushButton.paintEvent(self, ev) super().paintEvent(ev)
p = QtGui.QPainter(self) p = QtGui.QPainter(self)
p.setBrush(QtGui.QBrush(QtGui.QColor(0,0,0))) p.setBrush(QtGui.QBrush(QtGui.QColor(0,0,0)))
p.drawEllipse(self.spotPos.x()-3,self.spotPos.y()-3,6,6) p.drawEllipse(self.spotPos.x()-3,self.spotPos.y()-3,6,6)
def resizeEvent(self, ev): def resizeEvent(self, ev):
self.setState(*self.state) self.setState(*self.state)
QtGui.QPushButton.resizeEvent(self, ev) super().resizeEvent(ev)

View File

@ -32,7 +32,7 @@ class PathButton(QtGui.QPushButton):
self.update() self.update()
def paintEvent(self, ev): def paintEvent(self, ev):
QtGui.QPushButton.paintEvent(self, ev) super().paintEvent(ev)
margin = self.margin margin = self.margin
geom = QtCore.QRectF(0, 0, self.width(), self.height()).adjusted(margin, margin, -margin, -margin) geom = QtCore.QRectF(0, 0, self.width(), self.height()).adjusted(margin, margin, -margin, -margin)
rect = self.path.boundingRect() rect = self.path.boundingRect()

View File

@ -195,7 +195,7 @@ class ProgressDialog(QtGui.QProgressDialog):
if self._nestingReady: if self._nestingReady:
# don't let progress dialog manage widgets anymore. # don't let progress dialog manage widgets anymore.
return return
return QtGui.QProgressDialog.resizeEvent(self, ev) return super().resizeEvent(ev)
## wrap all other functions to make sure they aren't being called from non-gui threads ## wrap all other functions to make sure they aren't being called from non-gui threads

View File

@ -1,9 +1,6 @@
from ..Qt import QtGui, QtCore, QT_LIB from ..Qt import QtGui, QtCore, QT_LIB
if QT_LIB in ['PyQt4', 'PyQt5']: if QT_LIB.startswith('PyQt'):
try: from ..Qt import sip
from PyQt5 import sip
except ImportError:
import sip
from .. import multiprocess as mp from .. import multiprocess as mp
from .GraphicsView import GraphicsView from .GraphicsView import GraphicsView
from .. import CONFIG_OPTIONS from .. import CONFIG_OPTIONS
@ -12,55 +9,6 @@ import mmap, tempfile, ctypes, atexit, sys, random
__all__ = ['RemoteGraphicsView'] __all__ = ['RemoteGraphicsView']
class SerializableWheelEvent:
"""
Contains all information of a QWheelEvent, is serializable and can generate QWheelEvents.
Methods have the functionality of their QWheelEvent equivalent.
"""
def __init__(self, _pos, _globalPos, _delta, _buttons, _modifiers, _orientation):
self._pos = _pos
self._globalPos = _globalPos
self._delta = _delta
self._buttons = _buttons
self._modifiers = _modifiers
self._orientation_vertical = _orientation == QtCore.Qt.Vertical
def pos(self):
return self._pos
def globalPos(self):
return self._globalPos
def delta(self):
return self._delta
def orientation(self):
if self._orientation_vertical:
return QtCore.Qt.Vertical
else:
return QtCore.Qt.Horizontal
def angleDelta(self):
if self._orientation_vertical:
return QtCore.QPoint(0, self._delta)
else:
return QtCore.QPoint(self._delta, 0)
def buttons(self):
return QtCore.Qt.MouseButtons(self._buttons)
def modifiers(self):
return QtCore.Qt.KeyboardModifiers(self._modifiers)
def toQWheelEvent(self):
"""
Generate QWheelEvent from SerializableWheelEvent.
"""
if QT_LIB in ['PyQt4', 'PySide']:
return QtGui.QWheelEvent(self.pos(), self.globalPos(), self.delta(), self.buttons(), self.modifiers(), self.orientation())
else:
return QtGui.QWheelEvent(self.pos(), self.globalPos(), QtCore.QPoint(), self.angleDelta(), self.delta(), self.orientation(), self.buttons(), self.modifiers())
class RemoteGraphicsView(QtGui.QWidget): class RemoteGraphicsView(QtGui.QWidget):
""" """
@ -114,7 +62,7 @@ class RemoteGraphicsView(QtGui.QWidget):
setattr(self, method, getattr(self._view, method)) setattr(self, method, getattr(self._view, method))
def resizeEvent(self, ev): def resizeEvent(self, ev):
ret = QtGui.QWidget.resizeEvent(self, ev) ret = super().resizeEvent(ev)
self._view.resize(self.size(), _callSync='off') self._view.resize(self.size(), _callSync='off')
return ret return ret
@ -148,52 +96,60 @@ class RemoteGraphicsView(QtGui.QWidget):
p = QtGui.QPainter(self) p = QtGui.QPainter(self)
p.drawImage(self.rect(), self._img, QtCore.QRect(0, 0, self._img.width(), self._img.height())) p.drawImage(self.rect(), self._img, QtCore.QRect(0, 0, self._img.width(), self._img.height()))
p.end() p.end()
def serialize_mouse_common(self, ev):
if QT_LIB == 'PyQt6':
# PyQt6 can pickle MouseButtons and KeyboardModifiers but cannot cast to int
btns = ev.buttons()
mods = ev.modifiers()
else:
# PyQt5, PySide2, PySide6 cannot pickle MouseButtons and KeyboardModifiers
btns = int(ev.buttons())
mods = int(ev.modifiers())
return (btns, mods)
def serialize_mouse_event(self, ev):
# lpos, gpos = ev.localPos(), ev.screenPos()
# RemoteGraphicsView Renderer assumes to be at (0, 0)
gpos = lpos = ev.localPos()
btns, mods = self.serialize_mouse_common(ev)
return (ev.type(), lpos, gpos, ev.button(), btns, mods)
def serialize_wheel_event(self, ev):
# lpos, gpos = ev.position(), globalPosition()
# RemoteGraphicsView Renderer assumes to be at (0, 0)
gpos = lpos = ev.position()
btns, mods = self.serialize_mouse_common(ev)
return (lpos, gpos, ev.pixelDelta(), ev.angleDelta(), btns, mods, ev.phase(), ev.inverted())
def mousePressEvent(self, ev): def mousePressEvent(self, ev):
self._view.mousePressEvent(int(ev.type()), ev.pos(), ev.pos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off') self._view.mousePressEvent(self.serialize_mouse_event(ev), _callSync='off')
ev.accept() ev.accept()
return QtGui.QWidget.mousePressEvent(self, ev) return super().mousePressEvent(ev)
def mouseReleaseEvent(self, ev): def mouseReleaseEvent(self, ev):
self._view.mouseReleaseEvent(int(ev.type()), ev.pos(), ev.pos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off') self._view.mouseReleaseEvent(self.serialize_mouse_event(ev), _callSync='off')
ev.accept() ev.accept()
return QtGui.QWidget.mouseReleaseEvent(self, ev) return super().mouseReleaseEvent(ev)
def mouseMoveEvent(self, ev): def mouseMoveEvent(self, ev):
self._view.mouseMoveEvent(int(ev.type()), ev.pos(), ev.pos(), int(ev.button()), int(ev.buttons()), int(ev.modifiers()), _callSync='off') self._view.mouseMoveEvent(self.serialize_mouse_event(ev), _callSync='off')
ev.accept() ev.accept()
return QtGui.QWidget.mouseMoveEvent(self, ev) return super().mouseMoveEvent(ev)
def wheelEvent(self, ev): def wheelEvent(self, ev):
delta = 0 self._view.wheelEvent(self.serialize_wheel_event(ev), _callSync='off')
orientation = QtCore.Qt.Horizontal
if QT_LIB in ['PyQt4', 'PySide']:
delta = ev.delta()
orientation = ev.orientation()
else:
delta = ev.angleDelta().x()
if delta == 0:
orientation = QtCore.Qt.Vertical
delta = ev.angleDelta().y()
serializableEvent = SerializableWheelEvent(ev.pos(), ev.pos(), delta, int(ev.buttons()), int(ev.modifiers()), orientation)
self._view.wheelEvent(serializableEvent, _callSync='off')
ev.accept() ev.accept()
return QtGui.QWidget.wheelEvent(self, ev) return super().wheelEvent(ev)
def keyEvent(self, ev):
if self._view.keyEvent(int(ev.type()), int(ev.modifiers()), text, autorep, count):
ev.accept()
return QtGui.QWidget.keyEvent(self, ev)
def enterEvent(self, ev): def enterEvent(self, ev):
lws = ev.localPos(), ev.windowPos(), ev.screenPos() lws = ev.localPos(), ev.windowPos(), ev.screenPos()
self._view.enterEvent(lws, _callSync='off') self._view.enterEvent(lws, _callSync='off')
return QtGui.QWidget.enterEvent(self, ev) return super().enterEvent(ev)
def leaveEvent(self, ev): def leaveEvent(self, ev):
self._view.leaveEvent(int(ev.type()), _callSync='off') self._view.leaveEvent(ev.type(), _callSync='off')
return QtGui.QWidget.leaveEvent(self, ev) return super().leaveEvent(ev)
def remoteProcess(self): def remoteProcess(self):
"""Return the remote process handle. (see multiprocess.remoteproxy.RemoteEventHandler)""" """Return the remote process handle. (see multiprocess.remoteproxy.RemoteEventHandler)"""
@ -243,11 +199,11 @@ class Renderer(GraphicsView):
def update(self): def update(self):
self.img = None self.img = None
return GraphicsView.update(self) return super().update()
def resize(self, size): def resize(self, size):
oldSize = self.size() oldSize = self.size()
GraphicsView.resize(self, size) super().resize(size)
self.resizeEvent(QtGui.QResizeEvent(size, oldSize)) self.resizeEvent(QtGui.QResizeEvent(size, oldSize))
self.update() self.update()
@ -275,62 +231,60 @@ class Renderer(GraphicsView):
self.shm.resize(size) self.shm.resize(size)
## render the scene directly to shared memory ## render the scene directly to shared memory
ctypes_obj = ctypes.c_char.from_buffer(self.shm, 0)
if QT_LIB.startswith('PySide'): if QT_LIB.startswith('PySide'):
ch = ctypes.c_char.from_buffer(self.shm, 0) # PySide2, PySide6
self.img = QtGui.QImage(ch, self.width(), self.height(), QtGui.QImage.Format_ARGB32) img_ptr = ctypes_obj
else: else:
address = ctypes.addressof(ctypes.c_char.from_buffer(self.shm, 0)) # PyQt5, PyQt6
img_ptr = sip.voidptr(ctypes.addressof(ctypes_obj))
if QT_LIB == 'PyQt6':
img_ptr.setsize(size)
self.img = QtGui.QImage(img_ptr, self.width(), self.height(), QtGui.QImage.Format_ARGB32)
# different versions of pyqt have different requirements here..
try:
self.img = QtGui.QImage(sip.voidptr(address), self.width(), self.height(), QtGui.QImage.Format_ARGB32)
except TypeError:
try:
self.img = QtGui.QImage(memoryview(buffer(self.shm)), self.width(), self.height(), QtGui.QImage.Format_ARGB32)
except TypeError:
# Works on PyQt 4.9.6
self.img = QtGui.QImage(address, self.width(), self.height(), QtGui.QImage.Format_ARGB32)
self.img.fill(0xffffffff) self.img.fill(0xffffffff)
p = QtGui.QPainter(self.img) p = QtGui.QPainter(self.img)
self.render(p, self.viewRect(), self.rect()) self.render(p, self.viewRect(), self.rect())
p.end() p.end()
self.sceneRendered.emit((self.width(), self.height(), self.shm.size(), self.shmFileName())) self.sceneRendered.emit((self.width(), self.height(), self.shm.size(), self.shmFileName()))
def mousePressEvent(self, typ, pos, gpos, btn, btns, mods): def deserialize_mouse_event(self, mouse_event):
typ = QtCore.QEvent.Type(typ) typ, pos, gpos, btn, btns, mods = mouse_event
btn = QtCore.Qt.MouseButton(btn) typ = QtCore.QEvent.Type(typ) # this line needed by PyQt5 only
btns = QtCore.Qt.MouseButtons(btns) btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods) mods = QtCore.Qt.KeyboardModifiers(mods)
return GraphicsView.mousePressEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods)) return QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods)
def mouseMoveEvent(self, typ, pos, gpos, btn, btns, mods): def deserialize_wheel_event(self, wheel_event):
typ = QtCore.QEvent.Type(typ) pos, gpos, pixelDelta, angleDelta, btns, mods, scrollPhase, inverted = wheel_event
btn = QtCore.Qt.MouseButton(btn)
btns = QtCore.Qt.MouseButtons(btns) btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods) mods = QtCore.Qt.KeyboardModifiers(mods)
return GraphicsView.mouseMoveEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods)) return QtGui.QWheelEvent(pos, gpos, pixelDelta, angleDelta, btns, mods, scrollPhase, inverted)
def mouseReleaseEvent(self, typ, pos, gpos, btn, btns, mods): def mousePressEvent(self, mouse_event):
typ = QtCore.QEvent.Type(typ) ev = self.deserialize_mouse_event(mouse_event)
btn = QtCore.Qt.MouseButton(btn) return super().mousePressEvent(ev)
btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods) def mouseMoveEvent(self, mouse_event):
return GraphicsView.mouseReleaseEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods)) ev = self.deserialize_mouse_event(mouse_event)
return super().mouseMoveEvent(ev)
def mouseReleaseEvent(self, mouse_event):
ev = self.deserialize_mouse_event(mouse_event)
return super().mouseReleaseEvent(ev)
def wheelEvent(self, ev): def wheelEvent(self, wheel_event):
return GraphicsView.wheelEvent(self, ev.toQWheelEvent()) ev = self.deserialize_wheel_event(wheel_event)
return super().wheelEvent(ev)
def keyEvent(self, typ, mods, text, autorep, count):
typ = QtCore.QEvent.Type(typ)
mods = QtCore.Qt.KeyboardModifiers(mods)
GraphicsView.keyEvent(self, QtGui.QKeyEvent(typ, mods, text, autorep, count))
return ev.accepted()
def enterEvent(self, lws): def enterEvent(self, lws):
ev = QtGui.QEnterEvent(*lws) ev = QtGui.QEnterEvent(*lws)
return GraphicsView.enterEvent(self, ev) return super().enterEvent(ev)
def leaveEvent(self, typ): def leaveEvent(self, typ):
ev = QtCore.QEvent(QtCore.QEvent.Type(typ)) typ = QtCore.QEvent.Type(typ) # this line needed by PyQt5 only
return GraphicsView.leaveEvent(self, ev) ev = QtCore.QEvent(typ)
return super().leaveEvent(ev)

View File

@ -114,7 +114,7 @@ class SpinBox(QtGui.QAbstractSpinBox):
self.editingFinished.connect(self.editingFinishedEvent) self.editingFinished.connect(self.editingFinishedEvent)
def event(self, ev): def event(self, ev):
ret = QtGui.QAbstractSpinBox.event(self, ev) ret = super().event(ev)
if ev.type() == QtCore.QEvent.KeyPress and ev.key() == QtCore.Qt.Key_Return: if ev.type() == QtCore.QEvent.KeyPress and ev.key() == QtCore.Qt.Key_Return:
ret = True ## For some reason, spinbox pretends to ignore return key press ret = True ## For some reason, spinbox pretends to ignore return key press
return ret return ret
@ -596,7 +596,7 @@ class SpinBox(QtGui.QAbstractSpinBox):
def paintEvent(self, ev): def paintEvent(self, ev):
self._updateHeight() self._updateHeight()
QtGui.QAbstractSpinBox.paintEvent(self, ev) super().paintEvent(ev)
class ErrorBox(QtGui.QWidget): class ErrorBox(QtGui.QWidget):

View File

@ -366,7 +366,7 @@ class TableWidget(QtGui.QTableWidget):
ev.accept() ev.accept()
self.copySel() self.copySel()
else: else:
QtGui.QTableWidget.keyPressEvent(self, ev) super().keyPressEvent(ev)
def handleItemChanged(self, item): def handleItemChanged(self, item):
item.itemChanged() item.itemChanged()

View File

@ -144,7 +144,7 @@ class TreeWidget(QtGui.QTreeWidget):
return items return items
def dropEvent(self, ev): def dropEvent(self, ev):
QtGui.QTreeWidget.dropEvent(self, ev) super().dropEvent(ev)
self.updateDropFlags() self.updateDropFlags()
def updateDropFlags(self): def updateDropFlags(self):

View File

@ -58,7 +58,7 @@ class ValueLabel(QtGui.QLabel):
def paintEvent(self, ev): def paintEvent(self, ev):
self.setText(self.generateText()) self.setText(self.generateText())
return QtGui.QLabel.paintEvent(self, ev) return super().paintEvent(ev)
def generateText(self): def generateText(self):
if len(self.values) == 0: if len(self.values) == 0: