-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix a bug with the Qt5 backend with mixed resolution displays #8931
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix a bug with the Qt5 backend with mixed resolution displays #8931
Conversation
e143f62
to
05bdbc4
Compare
When mixed-resolution displays are present, the _dpi_ratio attribute on the canvas may change between paintEvents, which means that we need to change the size of the canvas. However, the underlying canvas is only resized if a resizeEvent is emitted, so we check whether _dpi_ratio has changed between paintEvents, and if so we emit a fake resizeEvent for the widget.
05bdbc4
to
f8cb5c9
Compare
# We use self.resizeEvent here instead of QApplication.postEvent | ||
# since the latter doesn't guarantee that the event will be emitted | ||
# straight away, and this causes visual delays in the changes. | ||
self.resizeEvent(event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this also trigger a paint event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might do - I'm investigating
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently not - at least the paintEvent method does not get called again as a result.
@tacaswell @efiring - I think I've got things behaving as they should: with mixed resolution displays, the plots look the same on all displays! There were fundamentally two issues here:
My approach is to keep track in paintEvent of what the last dpi_ratio was when the canvas was drawn. If it has changed, the figure DPI is updated, then the canvas size. However, note that changing the DPI normally causes the canvas to be resized, which we deal with ourselves already, so I've added a new
This is ready for review. |
776c940
to
f3c54a0
Compare
Similarly to resizeEvent, we tell _set_dpi to not change the canvas size since we are doing it ourselves.
b510f19
to
7f4a73a
Compare
… change when _dpi_ratio changes
I think the AppVeyor failure is unrelated? (other PRs seem to suffer from it) |
@@ -171,6 +198,10 @@ def __init__(self, figure): | |||
self.figure._original_dpi = self.figure.dpi | |||
self.figure.dpi = self._dpi_ratio * self.figure._original_dpi | |||
|
|||
def _update_figure_dpi(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use this in the __init__
above as well (and get rid of the hasattr
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! :)
@tacaswell - change implemented, and all tests are passing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 can confirm the original bug, and that this fixes it (using a retina Macbook and non-retina external screen)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is not passing for me.
Plus a few minor tweaks.
# mixed resolution displays if dpi_ratio is changing between painting | ||
# events. | ||
if (self._dpi_ratio_prev is None or | ||
self._dpi_ratio != self._dpi_ratio_prev): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under-indented.
assert size.width() == 200 | ||
assert size.height() == 80 | ||
assert_equal(qt_canvas.get_width_height(), (600, 240)) | ||
assert_equal(fig.get_size_inches(), (5, 2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A regular assert
would be fine here; you didn't need to import assert_equal
.
qApp.processEvents() | ||
|
||
# The DPI and the renderer width/height change | ||
assert fig.dpi == 240 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't passing for me here; I think you need to do a little more to trigger an update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, this seems to pass on the CI though - or does the test not get run on the CI? What platform and exact Qt version are you using?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any obvious skips in the CI, but you can confirm with @anntzer that the tests should be running. The odd thing is I don't see any Qt4 skips and one would normally preclude the other; maybe they just luckily ran on different processes?
I am running on Fedora+conda using the latest defaults
Qt package (conda-forge
's Qt seems to be broken) 5.6.2-5 with Python 3.6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost certainly related to #8659 (causing some of the tests not being run).
When mixed-resolution displays are present, the _dpi_ratio attribute on the canvas may change between paintEvents, which means that we need to change the size of the canvas. However, the underlying canvas is only resized if a resizeEvent is emitted, so we check whether _dpi_ratio has changed between paintEvents, and if so we emit a fake resizeEvent for the widget.
Fixes #8061
Note that while this fixes the issue described in #8061 which was that one could end up with weird visual issues such as:
the plot for the lower DPI display still has too large fonts/linewidths, but I think that is a separate bug, which I'll try and fix in another PR.
cc @tacaswell @efiring