重新启动包含 matplotlib 的 PyQt QApplication canvas
Restarting PyQt QApplication that contains matplotlib canvas
您可以看到 window 在使用 QApplicaiton.exit() 时仍然存在,然后在第二次尝试重新启动时崩溃。认为这可能是一个线程问题,但当我尝试更细致的方法在退出前关闭 matplotlib canvas 时,它似乎仍然存在。
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
class MainWindow(QtWidgets.QMainWindow):
REBOOT_CODE = -654321
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.sc = MplCanvas(self, width=5, height=4, dpi=100)
self.sc.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
button = QtWidgets.QPushButton('reload', self)
button.clicked.connect(lambda: self.reloadapp())
layout = QtWidgets.QVBoxLayout()
layout.addWidget(button)
layout.addWidget(self.sc)
# Create a placeholder widget
widget = QtWidgets.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
def reloadapp(self):
self.sc.close_event()
QtWidgets.QApplication.exit( MainWindow.REBOOT_CODE )
if __name__ == '__main__':
exit_code = MainWindow.REBOOT_CODE
while exit_code == MainWindow.REBOOT_CODE:
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
app = None
问题是 app = None
并没有消除 QApplication,因为在 Python 中,另一个变量维护对象的引用就足够了,这样它就可以保持活动状态,而 matplotlib 会发生这种情况维护 QApplication 的引用。一种可能的解决方案是使用 sip.delete 删除 C++ 对象。
另一个错误是您没有将 app.exec_()
returns 分配给 exit_code
,这会产生无限循环。另一方面,没有必要使用 self.sc.close_event ()
.
from PyQt5 import QtCore, QtGui, QtWidgets, sip
if __name__ == "__main__":
exit_code = MainWindow.REBOOT_CODE
while exit_code == MainWindow.REBOOT_CODE:
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
exit_code = app.exec_()
sip.delete(app)
app = None
您可以看到 window 在使用 QApplicaiton.exit() 时仍然存在,然后在第二次尝试重新启动时崩溃。认为这可能是一个线程问题,但当我尝试更细致的方法在退出前关闭 matplotlib canvas 时,它似乎仍然存在。
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
class MainWindow(QtWidgets.QMainWindow):
REBOOT_CODE = -654321
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.sc = MplCanvas(self, width=5, height=4, dpi=100)
self.sc.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
button = QtWidgets.QPushButton('reload', self)
button.clicked.connect(lambda: self.reloadapp())
layout = QtWidgets.QVBoxLayout()
layout.addWidget(button)
layout.addWidget(self.sc)
# Create a placeholder widget
widget = QtWidgets.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
def reloadapp(self):
self.sc.close_event()
QtWidgets.QApplication.exit( MainWindow.REBOOT_CODE )
if __name__ == '__main__':
exit_code = MainWindow.REBOOT_CODE
while exit_code == MainWindow.REBOOT_CODE:
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
app = None
问题是 app = None
并没有消除 QApplication,因为在 Python 中,另一个变量维护对象的引用就足够了,这样它就可以保持活动状态,而 matplotlib 会发生这种情况维护 QApplication 的引用。一种可能的解决方案是使用 sip.delete 删除 C++ 对象。
另一个错误是您没有将 app.exec_()
returns 分配给 exit_code
,这会产生无限循环。另一方面,没有必要使用 self.sc.close_event ()
.
from PyQt5 import QtCore, QtGui, QtWidgets, sip
if __name__ == "__main__":
exit_code = MainWindow.REBOOT_CODE
while exit_code == MainWindow.REBOOT_CODE:
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
exit_code = app.exec_()
sip.delete(app)
app = None