Skip to content

Commit e987b61

Browse files
committed
qt: Use better devicePixelRatio event to refresh scaling
With Qt 6.6, there is an event on the window that signals when the devicePixelRatio has changed. This is better than before when we had to rely on the underlying `QScreen`, which doesn't correctly refresh when a fractional scale is used. Fixes matplotlib#30218
1 parent 95db12f commit e987b61

File tree

2 files changed

+25
-7
lines changed

2 files changed

+25
-7
lines changed

lib/matplotlib/backends/backend_qt.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,21 @@ def _update_screen(self, screen):
262262
screen.physicalDotsPerInchChanged.connect(self._update_pixel_ratio)
263263
screen.logicalDotsPerInchChanged.connect(self._update_pixel_ratio)
264264

265+
def eventFilter(self, source, event):
266+
if event.type() == QtCore.QEvent.Type.DevicePixelRatioChange:
267+
self._update_pixel_ratio()
268+
return super().eventFilter(source, event)
269+
265270
def showEvent(self, event):
266271
# Set up correct pixel ratio, and connect to any signal changes for it,
267272
# once the window is shown (and thus has these attributes).
268273
window = self.window().windowHandle()
269-
window.screenChanged.connect(self._update_screen)
270-
self._update_screen(window.screen())
274+
current_version = tuple(int(x) for x in QtCore.qVersion().split('.', 2)[:2])
275+
if current_version >= (6, 6):
276+
window.installEventFilter(self)
277+
else:
278+
window.screenChanged.connect(self._update_screen)
279+
self._update_screen(window.screen())
271280

272281
def set_cursor(self, cursor):
273282
# docstring inherited

lib/matplotlib/tests/test_backend_qt.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from matplotlib import _c_internal_utils
1616

1717
try:
18+
from matplotlib.backends.qt_compat import QtCore # type: ignore[attr-defined] # noqa: E501, F401
1819
from matplotlib.backends.qt_compat import QtGui # type: ignore[attr-defined] # noqa: E501, F401
1920
from matplotlib.backends.qt_compat import QtWidgets # type: ignore[attr-defined]
2021
from matplotlib.backends.qt_editor import _formlayout
@@ -154,11 +155,19 @@ def test_device_pixel_ratio_change():
154155
def set_device_pixel_ratio(ratio):
155156
p.return_value = ratio
156157

157-
# The value here doesn't matter, as we can't mock the C++ QScreen
158-
# object, but can override the functional wrapper around it.
159-
# Emitting this event is simply to trigger the DPI change handler
160-
# in Matplotlib in the same manner that it would occur normally.
161-
screen.logicalDotsPerInchChanged.emit(96)
158+
current_version = tuple(int(x) for x in QtCore.qVersion().split('.', 2)[:2])
159+
if current_version >= (6, 6):
160+
# Emitting this event is simply to trigger the DPI change handler
161+
# in Matplotlib in the same manner that it would occur normally.
162+
qt_canvas.eventFilter(
163+
None,
164+
QtCore.QEvent(QtCore.QEvent.Type.DevicePixelRatioChange))
165+
else:
166+
# The value here doesn't matter, as we can't mock the C++ QScreen
167+
# object, but can override the functional wrapper around it.
168+
# Emitting this event is simply to trigger the DPI change handler
169+
# in Matplotlib in the same manner that it would occur normally.
170+
screen.logicalDotsPerInchChanged.emit(96)
162171

163172
qt_canvas.draw()
164173
qt_canvas.flush_events()

0 commit comments

Comments
 (0)