123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- """
- Render to qt from agg.
- """
- import ctypes
- from matplotlib.transforms import Bbox
- from .. import cbook
- from .backend_agg import FigureCanvasAgg
- from .backend_qt5 import (
- QtCore, QtGui, QtWidgets, _BackendQT5, FigureCanvasQT, FigureManagerQT,
- NavigationToolbar2QT, backend_version)
- from .qt_compat import QT_API
- class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT):
- def __init__(self, figure):
- # Must pass 'figure' as kwarg to Qt base class.
- super().__init__(figure=figure)
- def paintEvent(self, event):
- """
- Copy the image from the Agg canvas to the qt.drawable.
- In Qt, all drawing should be done inside of here when a widget is
- shown onscreen.
- """
- if self._update_dpi():
- # The dpi update triggered its own paintEvent.
- return
- self._draw_idle() # Only does something if a draw is pending.
- # If the canvas does not have a renderer, then give up and wait for
- # FigureCanvasAgg.draw(self) to be called.
- if not hasattr(self, 'renderer'):
- return
- painter = QtGui.QPainter(self)
- # See documentation of QRect: bottom() and right() are off by 1, so use
- # left() + width() and top() + height().
- rect = event.rect()
- # scale rect dimensions using the screen dpi ratio to get
- # correct values for the Figure coordinates (rather than QT5's coords)
- width = rect.width() * self._dpi_ratio
- height = rect.height() * self._dpi_ratio
- left, top = self.mouseEventCoords(rect.topLeft())
- # shift the "top" by the height of the image to get the
- # correct corner for our coordinate system
- bottom = top - height
- # same with the right side of the image
- right = left + width
- # create a buffer using the image bounding box
- bbox = Bbox([[left, bottom], [right, top]])
- reg = self.copy_from_bbox(bbox)
- buf = cbook._unmultiplied_rgba8888_to_premultiplied_argb32(
- memoryview(reg))
- # clear the widget canvas
- painter.eraseRect(rect)
- qimage = QtGui.QImage(buf, buf.shape[1], buf.shape[0],
- QtGui.QImage.Format_ARGB32_Premultiplied)
- if hasattr(qimage, 'setDevicePixelRatio'):
- # Not available on Qt4 or some older Qt5.
- qimage.setDevicePixelRatio(self._dpi_ratio)
- # set origin using original QT coordinates
- origin = QtCore.QPoint(rect.left(), rect.top())
- painter.drawImage(origin, qimage)
- # Adjust the buf reference count to work around a memory
- # leak bug in QImage under PySide on Python 3.
- if QT_API in ('PySide', 'PySide2'):
- ctypes.c_long.from_address(id(buf)).value = 1
- self._draw_rect_callback(painter)
- painter.end()
- def blit(self, bbox=None):
- # docstring inherited
- # If bbox is None, blit the entire canvas. Otherwise
- # blit only the area defined by the bbox.
- if bbox is None and self.figure:
- bbox = self.figure.bbox
- # repaint uses logical pixels, not physical pixels like the renderer.
- l, b, w, h = [pt / self._dpi_ratio for pt in bbox.bounds]
- t = b + h
- self.repaint(l, self.renderer.height / self._dpi_ratio - t, w, h)
- def print_figure(self, *args, **kwargs):
- super().print_figure(*args, **kwargs)
- self.draw()
- @_BackendQT5.export
- class _BackendQT5Agg(_BackendQT5):
- FigureCanvas = FigureCanvasQTAgg
|