Skip to content

Commit 98d5753

Browse files
committed
Let QPaintEvent tell us what region to repaint.
1 parent 4e8c7fe commit 98d5753

File tree

1 file changed

+29
-27
lines changed

1 file changed

+29
-27
lines changed

lib/matplotlib/backends/backend_qt5agg.py

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ def __init__(self, figure):
3535
super(FigureCanvasQTAggBase, self).__init__(figure=figure)
3636
self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
3737
self._agg_draw_pending = False
38-
self._bbox_queue = []
38+
self._bbox_queue = [] # Only kept for backcompatibility, but unused.
39+
self._erase_before_paint = False
3940
self._drawRect = None
4041

4142
def drawRectangle(self, rect):
@@ -50,7 +51,7 @@ def drawRectangle(self, rect):
5051
def blitbox(self):
5152
return self._bbox_queue
5253

53-
def paintEvent(self, e):
54+
def paintEvent(self, event):
5455
"""Copy the image from the Agg canvas to the qt.drawable.
5556
5657
In Qt, all drawing should be done inside of here when a widget is
@@ -60,32 +61,32 @@ def paintEvent(self, e):
6061
# FigureCanvasAgg.draw(self) to be called
6162
if not hasattr(self, 'renderer'):
6263
return
63-
64+
self._bbox_queue.clear()
6465
painter = QtGui.QPainter(self)
65-
66-
if self._bbox_queue:
67-
bbox_queue = self._bbox_queue
68-
else:
66+
rect = event.rect()
67+
left = rect.left()
68+
top = rect.top()
69+
width = rect.width()
70+
height = rect.height()
71+
if self._erase_before_paint:
6972
painter.eraseRect(self.rect())
70-
bbox_queue = [
71-
Bbox([[0, 0], [self.renderer.width, self.renderer.height]])]
72-
self._bbox_queue = []
73-
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
73+
self._erase_before_paint = False
74+
# See documentation of QRect: bottom() and right() are off by 1, so use
75+
# left() + width() and top() + height().
76+
bbox = Bbox([[left, self.renderer.height - (top + height)],
77+
[left + width, self.renderer.height - top]])
78+
reg = self.copy_from_bbox(bbox)
79+
buf = reg.to_string_argb()
80+
qimage = QtGui.QImage(buf, width, height, QtGui.QImage.Format_ARGB32)
81+
if hasattr(qimage, 'setDevicePixelRatio'):
82+
# Not available on Qt4 or some older Qt5.
83+
qimage.setDevicePixelRatio(self._dpi_ratio)
84+
origin = QtCore.QPoint(left, top)
85+
painter.drawImage(origin / self._dpi_ratio, qimage)
86+
# Adjust the buf reference count to work around a memory
87+
# leak bug in QImage under PySide on Python 3.
88+
if QT_API == 'PySide' and six.PY3:
89+
ctypes.c_long.from_address(id(buf)).value = 1
8990

9091
# draw the zoom rectangle to the QPainter
9192
if self._drawRect is not None:
@@ -103,6 +104,7 @@ def draw(self):
103104
# The Agg draw is done here; delaying causes problems with code that
104105
# uses the result of the draw() to update plot elements.
105106
super(FigureCanvasQTAggBase, self).draw()
107+
self._erase_before_paint = True
106108
self.update()
107109

108110
def draw_idle(self):
@@ -134,7 +136,7 @@ def blit(self, bbox=None):
134136
"""
135137
# If bbox is None, blit the entire canvas. Otherwise
136138
# blit only the area defined by the bbox.
137-
if bbox is None and self.figure:
139+
if bbox is None:
138140
bbox = self.figure.bbox
139141

140142
self._bbox_queue.append(bbox)

0 commit comments

Comments
 (0)