Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bbd3cf6

Browse files
jklymaktacaswell
authored andcommitted
Backport PR #15656: Support fractional HiDpi scaling with Qt backends
Merge pull request #15656 from timhoffm/qt-fractional-hidpi Support fractional HiDpi scaling with Qt backends Conflicts: lib/matplotlib/backends/backend_qt5.py lib/matplotlib/backends/qt_compat.py - only backport relevant changes
1 parent df4c5c1 commit bbd3cf6

File tree

5 files changed

+70
-21
lines changed

5 files changed

+70
-21
lines changed

lib/matplotlib/backends/backend_qt5.py

Lines changed: 6 additions & 10 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,
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
@@ -683,8 +680,7 @@ def _icon(self, name, color=None):
683680
if is_pyqt5():
684681
name = name.replace('.png', '_large.png')
685682
pm = QtGui.QPixmap(os.path.join(self.basedir, name))
686-
if hasattr(pm, 'setDevicePixelRatio'):
687-
pm.setDevicePixelRatio(self.canvas._dpi_ratio)
683+
qt_compat._setDevicePixelRatioF(pm, _devicePixelRatioF(self))
688684
if color is not None:
689685
mask = pm.createMaskFromColor(QtGui.QColor('black'),
690686
QtCore.Qt.MaskOutColor)

lib/matplotlib/backends/backend_qt5agg.py

Lines changed: 2 additions & 4 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)

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+
if 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)