77import six
88
99import ctypes
10- import traceback
1110
1211from matplotlib import cbook
1312from matplotlib .transforms import Bbox
1918from .qt_compat import QT_API
2019
2120
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 ):
3322
3423 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 )
3925 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 ()
4826
4927 @property
5028 @cbook .deprecated ("2.1" )
@@ -57,27 +35,10 @@ def paintEvent(self, e):
5735 In Qt, all drawing should be done inside of here when a widget is
5836 shown onscreen.
5937 """
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.
8040 return
41+ self ._draw_idle () # Only does something if a draw is pending.
8142
8243 # if the canvas does not have a renderer, then give up and wait for
8344 # FigureCanvasAgg.draw(self) to be called
@@ -100,72 +61,20 @@ def paintEvent(self, e):
10061 reg = self .copy_from_bbox (bbox )
10162 buf = reg .to_string_argb ()
10263 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
10368 if hasattr (qimage , 'setDevicePixelRatio' ):
10469 # Not available on Qt4 or some older Qt5.
10570 qimage .setDevicePixelRatio (self ._dpi_ratio )
10671 origin = QtCore .QPoint (l , self .renderer .height - t )
10772 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
11273
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 )
12075
12176 painter .end ()
12277
123- def draw (self ):
124- """Draw the figure with Agg, and queue a request for a Qt draw.
125- """
126- # The Agg draw is done here; delaying causes problems with code that
127- # uses the result of the draw() to update plot elements.
128- if self ._agg_is_drawing :
129- return
130-
131- self ._agg_is_drawing = True
132- try :
133- super (FigureCanvasQTAggBase , self ).draw ()
134- finally :
135- self ._agg_is_drawing = False
136- self .update ()
137-
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-
16978 def blit (self , bbox = None ):
17079 """Blit the region in bbox.
17180 """
@@ -182,25 +91,10 @@ def blit(self, bbox=None):
18291 self .repaint (l , self .renderer .height / self ._dpi_ratio - t , w , h )
18392
18493 def print_figure (self , * args , ** kwargs ):
185- super (FigureCanvasQTAggBase , self ).print_figure (* args , ** kwargs )
94+ super (FigureCanvasQTAgg , self ).print_figure (* args , ** kwargs )
18695 self .draw ()
18796
18897
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-
20498@_BackendQT5 .export
20599class _BackendQT5Agg (_BackendQT5 ):
206100 FigureCanvas = FigureCanvasQTAgg
0 commit comments