From 6a74cda44d8f467b4d5d2ac25e6ce7ac1efe3852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20W=C3=BCrtz?= Date: Wed, 19 Aug 2015 16:38:43 +0200 Subject: [PATCH] Qt: Redraw agg buffer in main thread. Implement FigureCanvasQTAggBase init. --- lib/matplotlib/backends/backend_qt4agg.py | 1 + lib/matplotlib/backends/backend_qt5.py | 18 ---------- lib/matplotlib/backends/backend_qt5agg.py | 43 ++++++++++++++++------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt4agg.py b/lib/matplotlib/backends/backend_qt4agg.py index b6830573c983..392d5d5cd073 100644 --- a/lib/matplotlib/backends/backend_qt4agg.py +++ b/lib/matplotlib/backends/backend_qt4agg.py @@ -69,6 +69,7 @@ def __init__(self, figure): if DEBUG: print('FigureCanvasQtAgg: ', figure) FigureCanvasQT.__init__(self, figure) + FigureCanvasQTAggBase.__init__(self, figure) FigureCanvasAgg.__init__(self, figure) self._drawRect = None self.blitbox = None diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 33f085f61cf7..38940c844f81 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -239,7 +239,6 @@ def __init__(self, figure): super(FigureCanvasQT, self).__init__(figure=figure) self.figure = figure self.setMouseTracking(True) - self._idle = True w, h = self.get_width_height() self.resize(w, h) @@ -415,23 +414,6 @@ def stop_event_loop(self): stop_event_loop.__doc__ = FigureCanvasBase.stop_event_loop_default.__doc__ - def draw_idle(self): - # This cannot be a call to 'update', we need a slightly longer - # delay, otherwise mouse releases from zooming, panning, or - # lassoing might not finish processing and will not redraw properly. - # We use the guard flag to prevent infinite calls to 'draw_idle' which - # happens with the 'stale' figure & axes callbacks. - d = self._idle - self._idle = False - - def idle_draw(*args): - try: - self.draw() - finally: - self._idle = True - if d: - QtCore.QTimer.singleShot(0, idle_draw) - class MainWindow(QtWidgets.QMainWindow): closing = QtCore.Signal() diff --git a/lib/matplotlib/backends/backend_qt5agg.py b/lib/matplotlib/backends/backend_qt5agg.py index 5b8e1117cb3f..f5d105e8bdb6 100644 --- a/lib/matplotlib/backends/backend_qt5agg.py +++ b/lib/matplotlib/backends/backend_qt5agg.py @@ -58,8 +58,12 @@ class FigureCanvasQTAggBase(object): Public attribute - figure - A Figure instance - """ + figure - A Figure instance + """ + + def __init__(self, figure): + super(FigureCanvasQTAggBase, self).__init__(figure=figure) + self._agg_draw_pending = False def drawRectangle(self, rect): self._drawRect = rect @@ -71,10 +75,6 @@ def paintEvent(self, e): In Qt, all drawing should be done inside of here when a widget is shown onscreen. """ - # If we have not rendered the Agg backend yet, do so now. - if not hasattr(self, 'renderer'): - FigureCanvasAgg.draw(self) - # FigureCanvasQT.paintEvent(self, e) if DEBUG: print('FigureCanvasQtAgg.paintEvent: ', self, @@ -142,15 +142,33 @@ def paintEvent(self, e): def draw(self): """ - Draw the figure with Agg, and queue a request - for a Qt draw. + Draw the figure with Agg, and queue a request for a Qt draw. """ - # The Agg draw is done here; delaying it until the paintEvent - # causes problems with code that uses the result of the - # draw() to update plot elements. + # The Agg draw is done here; delaying causes problems with code that + # uses the result of the draw() to update plot elements. FigureCanvasAgg.draw(self) self.update() + def draw_idle(self): + """ + Queue redraw of the Agg buffer and request Qt paintEvent. + """ + # The Agg draw needs to be handled by the same thread matplotlib + # modifies the scene graph from. Post Agg draw request to the + # current event loop in order to ensure thread affinity and to + # accumulate multiple draw requests from event handling. + # TODO: queued signal connection might be safer than singleShot + if not self._agg_draw_pending: + self._agg_draw_pending = True + QtCore.QTimer.singleShot(0, self.__draw_idle_agg) + + def __draw_idle_agg(self, *args): + try: + FigureCanvasAgg.draw(self) + self.update() + finally: + self._agg_draw_pending = False + def blit(self, bbox=None): """ Blit the region in bbox @@ -186,8 +204,7 @@ class FigureCanvasQTAgg(FigureCanvasQTAggBase, def __init__(self, figure): if DEBUG: print('FigureCanvasQtAgg: ', figure) - FigureCanvasQT.__init__(self, figure) - FigureCanvasAgg.__init__(self, figure) + super(FigureCanvasQTAgg, self).__init__(figure=figure) self._drawRect = None self.blitbox = None self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)