Skip to content

Commit c2af4f2

Browse files
committed
Qt: On draw(), request a full repaint.
(instead of just updating the blitboxes.)
1 parent 4e8c7fe commit c2af4f2

File tree

1 file changed

+36
-24
lines changed

1 file changed

+36
-24
lines changed

lib/matplotlib/backends/backend_qt5agg.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import six
88

99
import ctypes
10+
from threading import Lock
1011
import traceback
1112

1213
from matplotlib import cbook
@@ -34,9 +35,14 @@ class FigureCanvasQTAggBase(FigureCanvasAgg):
3435
def __init__(self, figure):
3536
super(FigureCanvasQTAggBase, self).__init__(figure=figure)
3637
self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
38+
self._drawRect = None
3739
self._agg_draw_pending = False
40+
# A list of Bboxes that will be repainted in the next paintEvent. As a
41+
# special case, an entry set to None requests the canvas to be fully
42+
# erased.
3843
self._bbox_queue = []
39-
self._drawRect = None
44+
# A mutex to protect all changes to _bbox_queue.
45+
self._bbox_queue_lock = Lock()
4046

4147
def drawRectangle(self, rect):
4248
if rect is not None:
@@ -48,7 +54,7 @@ def drawRectangle(self, rect):
4854
@property
4955
@cbook.deprecated("2.1")
5056
def blitbox(self):
51-
return self._bbox_queue
57+
return [bbox for bbox in self._bbox_queue if bbox is not None]
5258

5359
def paintEvent(self, e):
5460
"""Copy the image from the Agg canvas to the qt.drawable.
@@ -62,30 +68,30 @@ def paintEvent(self, e):
6268
return
6369

6470
painter = QtGui.QPainter(self)
65-
66-
if self._bbox_queue:
71+
with self._bbox_queue_lock:
6772
bbox_queue = self._bbox_queue
68-
else:
69-
painter.eraseRect(self.rect())
70-
bbox_queue = [
71-
Bbox([[0, 0], [self.renderer.width, self.renderer.height]])]
73+
self._bbox_queue = []
74+
7275
self._bbox_queue = []
7376
for bbox in bbox_queue:
74-
l, b, r, t = map(int, bbox.extents)
75-
w = r - l
76-
h = t - b
77-
reg = self.copy_from_bbox(bbox)
78-
buf = reg.to_string_argb()
79-
qimage = QtGui.QImage(buf, w, h, QtGui.QImage.Format_ARGB32)
80-
if hasattr(qimage, 'setDevicePixelRatio'):
81-
# Not available on Qt4 or some older Qt5.
82-
qimage.setDevicePixelRatio(self._dpi_ratio)
83-
origin = QtCore.QPoint(l, self.renderer.height - t)
84-
painter.drawImage(origin / self._dpi_ratio, qimage)
85-
# Adjust the buf reference count to work around a memory
86-
# leak bug in QImage under PySide on Python 3.
87-
if QT_API == 'PySide' and six.PY3:
88-
ctypes.c_long.from_address(id(buf)).value = 1
77+
if bbox is None:
78+
painter.eraseRect(self.rect())
79+
else:
80+
l, b, r, t = map(int, bbox.extents)
81+
w = r - l
82+
h = t - b
83+
reg = self.copy_from_bbox(bbox)
84+
buf = reg.to_string_argb()
85+
qimage = QtGui.QImage(buf, w, h, QtGui.QImage.Format_ARGB32)
86+
if hasattr(qimage, 'setDevicePixelRatio'):
87+
# Not available on Qt4 or some older Qt5.
88+
qimage.setDevicePixelRatio(self._dpi_ratio)
89+
origin = QtCore.QPoint(l, self.renderer.height - t)
90+
painter.drawImage(origin / self._dpi_ratio, qimage)
91+
# Adjust the buf reference count to work around a memory
92+
# leak bug in QImage under PySide on Python 3.
93+
if QT_API == 'PySide' and six.PY3:
94+
ctypes.c_long.from_address(id(buf)).value = 1
8995

9096
# draw the zoom rectangle to the QPainter
9197
if self._drawRect is not None:
@@ -103,6 +109,11 @@ def draw(self):
103109
# The Agg draw is done here; delaying causes problems with code that
104110
# uses the result of the draw() to update plot elements.
105111
super(FigureCanvasQTAggBase, self).draw()
112+
with self._bbox_queue_lock:
113+
# Erase the canvas and repaint everything.
114+
self._bbox_queue = [
115+
None,
116+
Bbox([[0, 0], [self.renderer.width, self.renderer.height]])]
106117
self.update()
107118

108119
def draw_idle(self):
@@ -137,7 +148,8 @@ def blit(self, bbox=None):
137148
if bbox is None and self.figure:
138149
bbox = self.figure.bbox
139150

140-
self._bbox_queue.append(bbox)
151+
with self._bbox_queue_lock:
152+
self._bbox_queue.append(bbox)
141153

142154
# repaint uses logical pixels, not physical pixels like the renderer.
143155
l, b, w, h = [pt / self._dpi_ratio for pt in bbox.bounds]

0 commit comments

Comments
 (0)