From e4079268e9e07ce7d1bfc433a07c02f631879c78 Mon Sep 17 00:00:00 2001 From: Martin Teichmann Date: Wed, 14 Nov 2012 12:19:10 +0100 Subject: [PATCH] use QMainWindow.closeEvent for close events The current code uses the QWidget.destroyed signal to emit a close event into matplotlib. This is a very bad idea, as it is a heavy abuse of Qt functionality. When a main window is closed in Qt, it and its children are deleted if the DeleteOnClose flag is set (which we did set). This causes the QWidget.destroyed signal to be called. Setting the DeleteOnClose flag is a very bad idea, since objects should only be deleted by the garbage collector. Soon after, PyQt4 will complain that "the underlying C++ object has been deleted", since the object is alive for python but dead for C++. This patch changes the machinery to use the QMainWindow.closeEvent to emit a close_event, which is what one actually wants. --- lib/matplotlib/backends/backend_qt4.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 006b957aa662..5d4cbef0a48b 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -208,18 +208,6 @@ def __init__( self, figure ): w,h = self.get_width_height() self.resize( w, h ) - # JDH: Note the commented out code below does not work as - # expected, because according to Pierre Raybaut, The reason is - # that PyQt fails (silently) to call a method of this object - # just before detroying it. Using a lambda function will work, - # exactly the same as using a function (which is not bound to - # the object to be destroyed). - # - #QtCore.QObject.connect(self, QtCore.SIGNAL('destroyed()'), - # self.close_event) - QtCore.QObject.connect(self, QtCore.SIGNAL('destroyed()'), - lambda: self.close_event()) - def __timerEvent(self, event): # hide until we can test and fix self.mpl_idle_event(event) @@ -377,6 +365,10 @@ def idle_draw(*args): self._idle = True if d: QtCore.QTimer.singleShot(0, idle_draw) +class MainWindow(QtGui.QMainWindow): + def closeEvent(self, event): + self.emit(QtCore.SIGNAL('closing()')) + class FigureManagerQT( FigureManagerBase ): """ Public attributes @@ -391,8 +383,9 @@ def __init__( self, canvas, num ): if DEBUG: print('FigureManagerQT.%s' % fn_name()) FigureManagerBase.__init__( self, canvas, num ) self.canvas = canvas - self.window = QtGui.QMainWindow() - self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose) + self.window = MainWindow() + self.window.connect(self.window, QtCore.SIGNAL('closing()'), + canvas.close_event) self.window.setWindowTitle("Figure %d" % num) image = os.path.join( matplotlib.rcParams['datapath'],'images','matplotlib.png' ) @@ -619,7 +612,6 @@ def draw_rubberband( self, event, x0, y0, x1, y1 ): def configure_subplots(self): self.adj_window = QtGui.QMainWindow() win = self.adj_window - win.setAttribute(QtCore.Qt.WA_DeleteOnClose) win.setWindowTitle("Subplot Configuration Tool") image = os.path.join( matplotlib.rcParams['datapath'],'images','matplotlib.png' )