Skip to content

Commit ff5c842

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 ff5c842

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
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 & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def on_key_press(event):
137137

138138

139139
@pytest.mark.backend('QtAgg', skip_on_importerror=True)
140-
def test_device_pixel_ratio_change():
140+
def test_device_pixel_ratio_change(qt_core):
141141
"""
142142
Make sure that if the pixel ratio changes, the figure dpi changes but the
143143
widget remains the same logical size.
@@ -154,11 +154,19 @@ def test_device_pixel_ratio_change():
154154
def set_device_pixel_ratio(ratio):
155155
p.return_value = ratio
156156

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

163171
qt_canvas.draw()
164172
qt_canvas.flush_events()
@@ -168,7 +176,6 @@ def set_device_pixel_ratio(ratio):
168176

169177
qt_canvas.manager.show()
170178
size = qt_canvas.size()
171-
screen = qt_canvas.window().windowHandle().screen()
172179
set_device_pixel_ratio(3)
173180

174181
# The DPI and the renderer width/height change

0 commit comments

Comments
 (0)