Skip to content

Commit aead584

Browse files
authored
Merge pull request #17641 from tacaswell/qt_backports
Qt backports
2 parents df4c5c1 + ff32cc7 commit aead584

File tree

6 files changed

+75
-25
lines changed

6 files changed

+75
-25
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,7 @@ def start_event_loop(self, timeout=0):
22932293
The event loop blocks until a callback function triggers
22942294
`stop_event_loop`, or *timeout* is reached.
22952295
2296-
If *timeout* is negative, never timeout.
2296+
If *timeout* is 0 or negative, never timeout.
22972297
22982298
Only interactive backends need to reimplement this method and it relies
22992299
on `flush_events` being properly implemented.

lib/matplotlib/backends/backend_qt5.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
import matplotlib.backends.qt_editor.figureoptions as figureoptions
1616
from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool
1717
from matplotlib.backend_managers import ToolManager
18-
18+
from . import qt_compat
1919
from .qt_compat import (
2020
QtCore, QtGui, QtWidgets, _isdeleted, _getSaveFileName,
21-
is_pyqt5, __version__, QT_API)
21+
is_pyqt5, __version__, QT_API, _setDevicePixelRatioF,
22+
_devicePixelRatioF)
23+
2224

2325
backend_version = __version__
2426

@@ -267,12 +269,7 @@ def _update_figure_dpi(self):
267269

268270
@property
269271
def _dpi_ratio(self):
270-
# Not available on Qt4 or some older Qt5.
271-
try:
272-
# self.devicePixelRatio() returns 0 in rare cases
273-
return self.devicePixelRatio() or 1
274-
except AttributeError:
275-
return 1
272+
return _devicePixelRatioF(self)
276273

277274
def _update_dpi(self):
278275
# As described in __init__ above, we need to be careful in cases with
@@ -454,8 +451,9 @@ def start_event_loop(self, timeout=0):
454451
if hasattr(self, "_event_loop") and self._event_loop.isRunning():
455452
raise RuntimeError("Event loop already running")
456453
self._event_loop = event_loop = QtCore.QEventLoop()
457-
if timeout:
458-
timer = QtCore.QTimer.singleShot(timeout * 1000, event_loop.quit)
454+
if timeout > 0:
455+
timer = QtCore.QTimer.singleShot(int(timeout * 1000),
456+
event_loop.quit)
459457
event_loop.exec_()
460458

461459
def stop_event_loop(self, event=None):
@@ -683,8 +681,7 @@ def _icon(self, name, color=None):
683681
if is_pyqt5():
684682
name = name.replace('.png', '_large.png')
685683
pm = QtGui.QPixmap(os.path.join(self.basedir, name))
686-
if hasattr(pm, 'setDevicePixelRatio'):
687-
pm.setDevicePixelRatio(self.canvas._dpi_ratio)
684+
_setDevicePixelRatioF(pm, _devicePixelRatioF(self))
688685
if color is not None:
689686
mask = pm.createMaskFromColor(QtGui.QColor('black'),
690687
QtCore.Qt.MaskOutColor)

lib/matplotlib/backends/backend_qt5agg.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from .backend_qt5 import (
1212
QtCore, QtGui, QtWidgets, _BackendQT5, FigureCanvasQT, FigureManagerQT,
1313
NavigationToolbar2QT, backend_version)
14-
from .qt_compat import QT_API
14+
from .qt_compat import QT_API, _setDevicePixelRatioF
1515

1616

1717
class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT):
@@ -64,9 +64,7 @@ def paintEvent(self, event):
6464

6565
qimage = QtGui.QImage(buf, buf.shape[1], buf.shape[0],
6666
QtGui.QImage.Format_ARGB32_Premultiplied)
67-
if hasattr(qimage, 'setDevicePixelRatio'):
68-
# Not available on Qt4 or some older Qt5.
69-
qimage.setDevicePixelRatio(self._dpi_ratio)
67+
_setDevicePixelRatioF(qimage, self._dpi_ratio)
7068
# set origin using original QT coordinates
7169
origin = QtCore.QPoint(rect.left(), rect.top())
7270
painter.drawImage(origin, qimage)
@@ -87,7 +85,7 @@ def blit(self, bbox=None):
8785
bbox = self.figure.bbox
8886

8987
# repaint uses logical pixels, not physical pixels like the renderer.
90-
l, b, w, h = [pt / self._dpi_ratio for pt in bbox.bounds]
88+
l, b, w, h = [int(pt / self._dpi_ratio) for pt in bbox.bounds]
9189
t = b + h
9290
self.repaint(l, self.renderer.height / self._dpi_ratio - t, w, h)
9391

lib/matplotlib/backends/backend_qt5cairo.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo
44
from .backend_qt5 import QtCore, QtGui, _BackendQT5, FigureCanvasQT
5-
from .qt_compat import QT_API
5+
from .qt_compat import QT_API, _setDevicePixelRatioF
66

77

88
class FigureCanvasQTCairo(FigureCanvasQT, FigureCanvasCairo):
@@ -19,8 +19,8 @@ def draw(self):
1919
def paintEvent(self, event):
2020
self._update_dpi()
2121
dpi_ratio = self._dpi_ratio
22-
width = dpi_ratio * self.width()
23-
height = dpi_ratio * self.height()
22+
width = int(dpi_ratio * self.width())
23+
height = int(dpi_ratio * self.height())
2424
if (width, height) != self._renderer.get_canvas_width_height():
2525
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
2626
self._renderer.set_ctx_from_surface(surface)
@@ -33,9 +33,7 @@ def paintEvent(self, event):
3333
# QImage under PySide on Python 3.
3434
if QT_API == 'PySide':
3535
ctypes.c_long.from_address(id(buf)).value = 1
36-
if hasattr(qimage, 'setDevicePixelRatio'):
37-
# Not available on Qt4 or some older Qt5.
38-
qimage.setDevicePixelRatio(dpi_ratio)
36+
_setDevicePixelRatioF(qimage, dpi_ratio)
3937
painter = QtGui.QPainter(self)
4038
painter.eraseRect(event.rect())
4139
painter.drawImage(0, 0, qimage)

lib/matplotlib/backends/qt_compat.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,38 @@ def is_pyqt5():
173173
# These globals are only defined for backcompatibility purposes.
174174
ETS = dict(pyqt=(QT_API_PYQTv2, 4), pyside=(QT_API_PYSIDE, 4),
175175
pyqt5=(QT_API_PYQT5, 5), pyside2=(QT_API_PYSIDE2, 5))
176-
QT_RC_MAJOR_VERSION = 5 if is_pyqt5() else 4
176+
177+
QT_RC_MAJOR_VERSION = int(QtCore.qVersion().split(".")[0])
178+
179+
180+
def _devicePixelRatioF(obj):
181+
"""
182+
Return obj.devicePixelRatioF() with graceful fallback for older Qt.
183+
184+
This can be replaced by the direct call when we require Qt>=5.6.
185+
"""
186+
try:
187+
# Not available on Qt<5.6
188+
return obj.devicePixelRatioF() or 1
189+
except AttributeError:
190+
pass
191+
try:
192+
# Not available on Qt4 or some older Qt5.
193+
# self.devicePixelRatio() returns 0 in rare cases
194+
return obj.devicePixelRatio() or 1
195+
except AttributeError:
196+
return 1
197+
198+
199+
def _setDevicePixelRatioF(obj, val):
200+
"""
201+
Call obj.setDevicePixelRatioF(val) with graceful fallback for older Qt.
202+
203+
This can be replaced by the direct call when we require Qt>=5.6.
204+
"""
205+
if hasattr(obj, 'setDevicePixelRatioF'):
206+
# Not available on Qt<5.6
207+
obj.setDevicePixelRatioF(val)
208+
elif hasattr(obj, 'setDevicePixelRatio'):
209+
# Not available on Qt4 or some older Qt5.
210+
obj.setDevicePixelRatio(val)

lib/matplotlib/tests/test_backend_qt.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,29 @@ def test_dpi_ratio_change():
253253
assert qt_canvas.get_width_height() == (600, 240)
254254
assert (fig.get_size_inches() == (5, 2)).all()
255255

256+
p.return_value = 1.5
257+
258+
assert qt_canvas._dpi_ratio == 1.5
259+
260+
qt_canvas.draw()
261+
qApp.processEvents()
262+
# this second processEvents is required to fully run the draw.
263+
# On `update` we notice the DPI has changed and trigger a
264+
# resize event to refresh, the second processEvents is
265+
# required to process that and fully update the window sizes.
266+
qApp.processEvents()
267+
268+
# The DPI and the renderer width/height change
269+
assert fig.dpi == 180
270+
assert qt_canvas.renderer.width == 900
271+
assert qt_canvas.renderer.height == 360
272+
273+
# The actual widget size and figure physical size don't change
274+
assert size.width() == 600
275+
assert size.height() == 240
276+
assert qt_canvas.get_width_height() == (600, 240)
277+
assert (fig.get_size_inches() == (5, 2)).all()
278+
256279

257280
@pytest.mark.backend('Qt5Agg')
258281
def test_subplottool():

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy