7
7
import six
8
8
9
9
import ctypes
10
- import traceback
11
10
12
11
from matplotlib import cbook
13
12
from matplotlib .transforms import Bbox
19
18
from .qt_compat import QT_API
20
19
21
20
22
- class FigureCanvasQTAggBase (FigureCanvasAgg ):
23
- """
24
- The canvas the figure renders into. Calls the draw and print fig
25
- methods, creates the renderers, etc...
26
-
27
- Attributes
28
- ----------
29
- figure : `matplotlib.figure.Figure`
30
- A high-level Figure instance
31
-
32
- """
21
+ class FigureCanvasQTAgg (FigureCanvasAgg , FigureCanvasQT ):
33
22
34
23
def __init__ (self , figure ):
35
- super (FigureCanvasQTAggBase , self ).__init__ (figure = figure )
36
- self .setAttribute (QtCore .Qt .WA_OpaquePaintEvent )
37
- self ._agg_draw_pending = False
38
- self ._agg_is_drawing = False
24
+ super (FigureCanvasQTAgg , self ).__init__ (figure = figure )
39
25
self ._bbox_queue = []
40
- self ._drawRect = None
41
-
42
- def drawRectangle (self , rect ):
43
- if rect is not None :
44
- self ._drawRect = [pt / self ._dpi_ratio for pt in rect ]
45
- else :
46
- self ._drawRect = None
47
- self .update ()
48
26
49
27
@property
50
28
@cbook .deprecated ("2.1" )
@@ -57,27 +35,10 @@ def paintEvent(self, e):
57
35
In Qt, all drawing should be done inside of here when a widget is
58
36
shown onscreen.
59
37
"""
60
- # if there is a pending draw, run it now as we need the updated render
61
- # to paint the widget
62
- if self ._agg_draw_pending :
63
- self .__draw_idle_agg ()
64
- # As described in __init__ above, we need to be careful in cases with
65
- # mixed resolution displays if dpi_ratio is changing between painting
66
- # events.
67
- if self ._dpi_ratio != self ._dpi_ratio_prev :
68
- # We need to update the figure DPI
69
- self ._update_figure_dpi ()
70
- self ._dpi_ratio_prev = self ._dpi_ratio
71
- # The easiest way to resize the canvas is to emit a resizeEvent
72
- # since we implement all the logic for resizing the canvas for
73
- # that event.
74
- event = QtGui .QResizeEvent (self .size (), self .size ())
75
- # We use self.resizeEvent here instead of QApplication.postEvent
76
- # since the latter doesn't guarantee that the event will be emitted
77
- # straight away, and this causes visual delays in the changes.
78
- self .resizeEvent (event )
79
- # resizeEvent triggers a paintEvent itself, so we exit this one.
38
+ if self ._update_dpi ():
39
+ # The dpi update triggered its own paintEvent.
80
40
return
41
+ self ._draw_idle () # Only does something if a draw is pending.
81
42
82
43
# if the canvas does not have a renderer, then give up and wait for
83
44
# FigureCanvasAgg.draw(self) to be called
@@ -100,23 +61,17 @@ def paintEvent(self, e):
100
61
reg = self .copy_from_bbox (bbox )
101
62
buf = reg .to_string_argb ()
102
63
qimage = QtGui .QImage (buf , w , h , QtGui .QImage .Format_ARGB32 )
64
+ # Adjust the buf reference count to work around a memory leak bug
65
+ # in QImage under PySide on Python 3.
66
+ if QT_API == 'PySide' and six .PY3 :
67
+ ctypes .c_long .from_address (id (buf )).value = 1
103
68
if hasattr (qimage , 'setDevicePixelRatio' ):
104
69
# Not available on Qt4 or some older Qt5.
105
70
qimage .setDevicePixelRatio (self ._dpi_ratio )
106
71
origin = QtCore .QPoint (l , self .renderer .height - t )
107
72
painter .drawImage (origin / self ._dpi_ratio , qimage )
108
- # Adjust the buf reference count to work around a memory
109
- # leak bug in QImage under PySide on Python 3.
110
- if QT_API == 'PySide' and six .PY3 :
111
- ctypes .c_long .from_address (id (buf )).value = 1
112
73
113
- # draw the zoom rectangle to the QPainter
114
- if self ._drawRect is not None :
115
- pen = QtGui .QPen (QtCore .Qt .black , 1 / self ._dpi_ratio ,
116
- QtCore .Qt .DotLine )
117
- painter .setPen (pen )
118
- x , y , w , h = self ._drawRect
119
- painter .drawRect (x , y , w , h )
74
+ self ._draw_rect_callback (painter )
120
75
121
76
painter .end ()
122
77
@@ -130,42 +85,11 @@ def draw(self):
130
85
131
86
self ._agg_is_drawing = True
132
87
try :
133
- super (FigureCanvasQTAggBase , self ).draw ()
88
+ super (FigureCanvasQTAgg , self ).draw ()
134
89
finally :
135
90
self ._agg_is_drawing = False
136
91
self .update ()
137
92
138
- def draw_idle (self ):
139
- """Queue redraw of the Agg buffer and request Qt paintEvent.
140
- """
141
- # The Agg draw needs to be handled by the same thread matplotlib
142
- # modifies the scene graph from. Post Agg draw request to the
143
- # current event loop in order to ensure thread affinity and to
144
- # accumulate multiple draw requests from event handling.
145
- # TODO: queued signal connection might be safer than singleShot
146
- if not (self ._agg_draw_pending or self ._agg_is_drawing ):
147
- self ._agg_draw_pending = True
148
- QtCore .QTimer .singleShot (0 , self .__draw_idle_agg )
149
-
150
- def __draw_idle_agg (self , * args ):
151
- # if nothing to do, bail
152
- if not self ._agg_draw_pending :
153
- return
154
- # we have now tried this function at least once, do not run
155
- # again until re-armed. Doing this here rather than after
156
- # protects against recursive calls triggered through self.draw
157
- # The recursive call is via `repaintEvent`
158
- self ._agg_draw_pending = False
159
- # if negative size, bail
160
- if self .height () < 0 or self .width () < 0 :
161
- return
162
- try :
163
- # actually do the drawing
164
- self .draw ()
165
- except Exception :
166
- # Uncaught exceptions are fatal for PyQt5, so catch them instead.
167
- traceback .print_exc ()
168
-
169
93
def blit (self , bbox = None ):
170
94
"""Blit the region in bbox.
171
95
"""
@@ -182,25 +106,10 @@ def blit(self, bbox=None):
182
106
self .repaint (l , self .renderer .height / self ._dpi_ratio - t , w , h )
183
107
184
108
def print_figure (self , * args , ** kwargs ):
185
- super (FigureCanvasQTAggBase , self ).print_figure (* args , ** kwargs )
109
+ super (FigureCanvasQTAgg , self ).print_figure (* args , ** kwargs )
186
110
self .draw ()
187
111
188
112
189
- class FigureCanvasQTAgg (FigureCanvasQTAggBase , FigureCanvasQT ):
190
- """
191
- The canvas the figure renders into. Calls the draw and print fig
192
- methods, creates the renderers, etc.
193
-
194
- Modified to import from Qt5 backend for new-style mouse events.
195
-
196
- Attributes
197
- ----------
198
- figure : `matplotlib.figure.Figure`
199
- A high-level Figure instance
200
-
201
- """
202
-
203
-
204
113
@_BackendQT5 .export
205
114
class _BackendQT5Agg (_BackendQT5 ):
206
115
FigureCanvas = FigureCanvasQTAgg
0 commit comments