Maracman
Maracman

Reputation: 13

Restarting PyQt QApplication that contains matplotlib canvas

You can see the window persists when using QApplicaiton.exit() and then crashes when it tries to restart the second time. Thought it could be a threading issue but it seems to still exist when I try more meticulous methods of closing the matplotlib canvas before exiting.

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

Upvotes: 1

Views: 60

Answers (1)

eyllanesc
eyllanesc

Reputation: 244003

The problem is that doing app = None does not eliminate the QApplication since in Python it is enough that another variable maintains the reference of the object so that it remains alive and that happens with matplotlib that maintains a reference of QApplication. One possible solution is to use sip.delete to delete the C++ object.

Another error is also that you do not assign what app.exec_() returns to exit_code which generates an infinite loop. On the other hand it is not necessary to use 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

Upvotes: 1

Related Questions