Patch/window handling (#468)

* Do not wrap PlotView/ImageView

There is no need to wrap PlotView/ImageView into QMainWindow, since
only purpose of the QMainWindow is some default menu toolbar & menu
handling, that is not used by PyQtGraph anyway.

Moreover, every parent-less Qt widget can become window, so this
change just use PlotView/ImageView as windows, removing extra
complexity, eg. method forwarding, self.win property.

Another benefit of this change, it that these windows get initial
dimensions and titles as they were designed in .ui file.

* Properly cleanup on ImageView.close()

We should not close explicitly child widgets or clear scene, otherwise
Qt will deallocate children views, and cause "wrapped C/C++ object of
type ImageItem has been deleted" error next time we call close()
and/or some other methods.

All children, including self.ui.roiPlot, self.ui.graphicsView will be
closed together with its parent, so there is no need to close them
explicitly.

So the purpose of close it to reclaim the memory, but not to make the existing ImageView object dysfunctional.

* Remove references to plot & image windows after close

PyQtGraph images and plots module list variables are currently holding
references to all plots and image windows returned directly from main
module. This does not seem to be documented however, and causes the Qt
windows to be not released from memory, even if user releases all own
references.

This change removes the references from images/plots list once window
is closed, so when there is no other reference, window and all related
memory is reclaimed.

* Change all UI forms title from Form to PyQtGraph

Co-authored-by: Ogi Moore <ognyan.moore@gmail.com>
This commit is contained in:
Adam Strzelecki 2020-06-01 20:23:18 +02:00 committed by GitHub
parent bb21791c71
commit 983cc1695e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 74 additions and 59 deletions

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">

View File

@ -41,7 +41,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.pixelModeCheck.setText(QtGui.QApplication.translate("Form", "pixel mode", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("Form", "Size", None, QtGui.QApplication.UnicodeUTF8))
self.randCheck.setText(QtGui.QApplication.translate("Form", "Randomize", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -36,7 +36,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.pixelModeCheck.setText(QtGui.QApplication.translate("Form", "pixel mode", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("Form", "Size", None, QtGui.QApplication.UnicodeUTF8))
self.randCheck.setText(QtGui.QApplication.translate("Form", "Randomize", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">

View File

@ -89,7 +89,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
self.graphicsSystemCombo.setItemText(0, _translate("Form", "default", None))
self.graphicsSystemCombo.setItemText(1, _translate("Form", "native", None))
self.graphicsSystemCombo.setItemText(2, _translate("Form", "raster", None))

View File

@ -78,7 +78,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
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"))

View File

@ -78,7 +78,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.graphicsSystemCombo.setItemText(0, QtGui.QApplication.translate("Form", "default", None, QtGui.QApplication.UnicodeUTF8))
self.graphicsSystemCombo.setItemText(1, QtGui.QApplication.translate("Form", "native", None, QtGui.QApplication.UnicodeUTF8))
self.graphicsSystemCombo.setItemText(2, QtGui.QApplication.translate("Form", "raster", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -413,12 +413,20 @@ def plot(*args, **kargs):
dataArgs[k] = kargs[k]
w = PlotWindow(**pwArgs)
w.sigClosed.connect(_plotWindowClosed)
if len(args) > 0 or len(dataArgs) > 0:
w.plot(*args, **dataArgs)
plots.append(w)
w.show()
return w
def _plotWindowClosed(w):
w.close()
try:
plots.remove(w)
except ValueError:
pass
def image(*args, **kargs):
"""
Create and return an :class:`ImageWindow <pyqtgraph.ImageWindow>`
@ -429,11 +437,19 @@ def image(*args, **kargs):
"""
mkQApp()
w = ImageWindow(*args, **kargs)
w.sigClosed.connect(_imageWindowClosed)
images.append(w)
w.show()
return w
show = image ## for backward compatibility
def _imageWindowClosed(w):
w.close()
try:
images.remove(w)
except ValueError:
pass
def dbg(*args, **kwds):
"""
Create a console window and begin watching for exceptions.

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="margin">

View File

@ -91,7 +91,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
self.autoRangeBtn.setText(_translate("Form", "Auto Range", None))
self.redirectCheck.setToolTip(_translate("Form", "Check to display all local items in a remote canvas.", None))
self.redirectCheck.setText(_translate("Form", "Redirect", None))

View File

@ -79,7 +79,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
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"))

View File

@ -80,7 +80,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.autoRangeBtn.setText(QtGui.QApplication.translate("Form", "Auto Range", None, QtGui.QApplication.UnicodeUTF8))
self.redirectCheck.setToolTip(QtGui.QApplication.translate("Form", "Check to display all local items in a remote canvas.", None, QtGui.QApplication.UnicodeUTF8))
self.redirectCheck.setText(QtGui.QApplication.translate("Form", "Redirect", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -17,7 +17,7 @@
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">

View File

@ -59,7 +59,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
self.translateLabel.setText(_translate("Form", "Translate:", None))
self.rotateLabel.setText(_translate("Form", "Rotate:", None))
self.scaleLabel.setText(_translate("Form", "Scale:", None))

View File

@ -46,7 +46,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.translateLabel.setText(_translate("Form", "Translate:"))
self.rotateLabel.setText(_translate("Form", "Rotate:"))
self.scaleLabel.setText(_translate("Form", "Scale:"))

View File

@ -46,7 +46,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.translateLabel.setText(QtGui.QApplication.translate("Form", "Translate:", None, QtGui.QApplication.UnicodeUTF8))
self.rotateLabel.setText(QtGui.QApplication.translate("Form", "Rotate:", None, QtGui.QApplication.UnicodeUTF8))
self.scaleLabel.setText(QtGui.QApplication.translate("Form", "Scale:", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="verticalSpacing">

View File

@ -69,7 +69,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
self.loadBtn.setText(_translate("Form", "Load..", None))
self.saveBtn.setText(_translate("Form", "Save", None))
self.saveAsBtn.setText(_translate("Form", "As..", None))

View File

@ -56,7 +56,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.loadBtn.setText(_translate("Form", "Load.."))
self.saveBtn.setText(_translate("Form", "Save"))
self.saveAsBtn.setText(_translate("Form", "As.."))

View File

@ -55,7 +55,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load..", None, QtGui.QApplication.UnicodeUTF8))
self.saveBtn.setText(QtGui.QApplication.translate("Form", "Save", None, QtGui.QApplication.UnicodeUTF8))
self.saveAsBtn.setText(QtGui.QApplication.translate("Form", "As..", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<widget class="QWidget" name="selInfoWidget" native="true">
<property name="geometry">

View File

@ -62,7 +62,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
from ..flowchart.FlowchartGraphicsView import FlowchartGraphicsView
from ..widgets.DataTreeWidget import DataTreeWidget

View File

@ -49,7 +49,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
from ..widgets.DataTreeWidget import DataTreeWidget
from ..flowchart.FlowchartGraphicsView import FlowchartGraphicsView

View File

@ -48,7 +48,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
from ..flowchart.FlowchartGraphicsView import FlowchartGraphicsView
from ..widgets.DataTreeWidget import DataTreeWidget

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<widget class="QGroupBox" name="averageGroup">
<property name="geometry">

View File

@ -148,7 +148,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
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).", None))
self.averageGroup.setTitle(_translate("Form", "Average", None))
self.clipToViewCheck.setToolTip(_translate("Form", "Plot only the portion of each curve that is visible. This assumes X values are uniformly spaced.", None))

View File

@ -135,7 +135,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
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."))

View File

@ -134,7 +134,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.averageGroup.setToolTip(QtGui.QApplication.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).", None, QtGui.QApplication.UnicodeUTF8))
self.averageGroup.setTitle(QtGui.QApplication.translate("Form", "Average", None, QtGui.QApplication.UnicodeUTF8))
self.clipToViewCheck.setToolTip(QtGui.QApplication.translate("Form", "Plot only the portion of each curve that is visible. This assumes X values are uniformly spaced.", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -17,7 +17,7 @@
</size>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">

View File

@ -78,7 +78,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
self.label.setText(_translate("Form", "Link Axis:", None))
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>", None))
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>", None))

View File

@ -65,7 +65,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
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>"))

View File

@ -64,7 +64,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("Form", "Link Axis:", None, QtGui.QApplication.UnicodeUTF8))
self.linkCombo.setToolTip(QtGui.QApplication.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>", None, QtGui.QApplication.UnicodeUTF8))
self.autoPercentSpin.setToolTip(QtGui.QApplication.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>", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -48,38 +48,39 @@ class TabWindow(QtGui.QMainWindow):
class PlotWindow(PlotWidget):
sigClosed = QtCore.Signal(object)
"""
(deprecated; use :class:`~pyqtgraph.PlotWidget` instead)
"""
def __init__(self, title=None, **kargs):
mkQApp()
self.win = QtGui.QMainWindow()
PlotWidget.__init__(self, **kargs)
self.win.setCentralWidget(self)
for m in ['resize']:
setattr(self, m, getattr(self.win, m))
if title is not None:
self.win.setWindowTitle(title)
self.win.show()
self.setWindowTitle(title)
self.show()
def closeEvent(self, event):
PlotWidget.closeEvent(self, event)
self.sigClosed.emit(self)
class ImageWindow(ImageView):
sigClosed = QtCore.Signal(object)
"""
(deprecated; use :class:`~pyqtgraph.ImageView` instead)
"""
def __init__(self, *args, **kargs):
mkQApp()
self.win = QtGui.QMainWindow()
self.win.resize(800,600)
ImageView.__init__(self)
if 'title' in kargs:
self.win.setWindowTitle(kargs['title'])
self.setWindowTitle(kargs['title'])
del kargs['title']
ImageView.__init__(self, self.win)
if len(args) > 0 or len(kargs) > 0:
self.setImage(*args, **kargs)
self.win.setCentralWidget(self)
for m in ['resize']:
setattr(self, m, getattr(self.win, m))
#for m in ['setImage', 'autoRange', 'addItem', 'removeItem', 'blackLevel', 'whiteLevel', 'imageItem']:
#setattr(self, m, getattr(self.cw, m))
self.win.show()
self.show()
def closeEvent(self, event):
ImageView.closeEvent(self, event)
self.sigClosed.emit(self)

View File

@ -411,11 +411,9 @@ class ImageView(QtGui.QWidget):
def close(self):
"""Closes the widget nicely, making sure to clear the graphics scene and release memory."""
self.ui.roiPlot.close()
self.ui.graphicsView.close()
self.scene.clear()
del self.image
del self.imageDisp
self.clear()
self.imageDisp = None
self.imageItem.setParent(None)
super(ImageView, self).close()
self.setParent(None)

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="margin">

View File

@ -146,7 +146,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
Form.setWindowTitle(_translate("Form", "PyQtGraph", None))
self.roiBtn.setText(_translate("Form", "ROI", None))
self.menuBtn.setText(_translate("Form", "Menu", None))
self.normGroup.setTitle(_translate("Form", "Normalization", None))

View File

@ -134,7 +134,7 @@ class Ui_Form(object):
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
Form.setWindowTitle(_translate("Form", "PyQtGraph"))
self.roiBtn.setText(_translate("Form", "ROI"))
self.menuBtn.setText(_translate("Form", "Norm"))
self.normGroup.setTitle(_translate("Form", "Normalization"))

View File

@ -132,7 +132,7 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQtGraph", None, QtGui.QApplication.UnicodeUTF8))
self.roiBtn.setText(QtGui.QApplication.translate("Form", "ROI", None, QtGui.QApplication.UnicodeUTF8))
self.menuBtn.setText(QtGui.QApplication.translate("Form", "Menu", None, QtGui.QApplication.UnicodeUTF8))
self.normGroup.setTitle(QtGui.QApplication.translate("Form", "Normalization", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>PyQtGraph</string>
</property>
<widget class="PlotWidget" name="widget" native="true">
<property name="geometry">