Skip to content

Fix keyboard event routing in Tk backend (fixes #13484, #14081, and #22028) #22077

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

Merged
merged 1 commit into from
Jan 25, 2022

Conversation

daniilS
Copy link
Contributor

@daniilS daniilS commented Jan 1, 2022

PR Summary

Currently, when using the Tk backend, Matplotlib sets the focus to the figure canvas upon its creation, as this is required to process keyboard events. As reported in #14081, this takes away the focus from other widgets when embedding a plot in a tkinter GUI, which creating a widget should never do (though the issue of other widgets being unable to take back the focus was fixed in Tk 8.6.11). Since a recent Python/Tk update, the focus doesn't get set to the canvas at all (#22028), though I cannot reproduce this outside of Matplotlib so can't tell what exactly caused this regression. Finally, the canvas has no visual indicator of having the focus, which makes it hard to get it to accept keyboard events again after tabbing out (#13484).

In this PR, the focus instead gets set to the canvas during the first call to plt.show(). It also gets set when the canvas receives a mouse click event, as is standard for widgets responding to keyboard events (e.g. entry widgets).

  • For pyplot windows, this fixes the regression from [Bug]: mpl with py3.10.1 - Interactive figures - Constrain pan/zoom to x/y axis not work #22028, and shouldn't behave any different apart from that
  • For embedded plots, this no longer steals the focus from other tkinter widgets, and the focus can instead be set by clicking the plot (or via canvas.get_tk_widget().focus_set()), as with any other widget
  • In both cases, it allows restoring the focus by clicking the canvas after tabbing out, or when dealing with multiple embedded plots.

I've also added a unit test, and updated the "embedding in tk" example to reflect this behaviour.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • New features are documented, with examples if plot related.
  • [N/A] New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • [N/A] API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
  • [N/A] Documentation is sphinx and numpydoc compliant (the docs should build without error).

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a while, please feel free to ping @matplotlib/developers or anyone who has commented on the PR. Most of our reviewers are volunteers and sometimes things fall through the cracks.

You can also join us on gitter for real-time discussion.

For details on testing, writing docs, and our review process, please see the developer guide

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@QuLogic QuLogic added the status: needs workflow approval For PRs from new contributors, from which GitHub blocks workflows by default. label Jan 6, 2022
@daniilS
Copy link
Contributor Author

daniilS commented Jan 6, 2022

Glad I added the test, looks like Tk is behaving differently on macOS. I'll need to set up a VM or see if I can get access to a Mac to figure out what exactly causes the failure.

@daniilS
Copy link
Contributor Author

daniilS commented Jan 6, 2022

Looks like on macOS, focus_get returns None when the popup window itself doesn't have the focus. Replacing it with focus_lastfor fixes this on my machine, let's see if it fixes the tests as well.

Copy link
Contributor

@richardsheridan richardsheridan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution!

The code and behavior of this patch are good, but the fact is that this is a breaking change for embedded users and we need to handle them appropriately. At a minimum the patch should be prominently featured in the release notes and not backported. It would also be nice to explicitly document this somewhere besides the example, somewhere that we already contrast other backend-specific quirks.

It may also be appropriate to do some kind of depreciation period before applying it. I'm happy to patch my own app fairly quickly but it may be more trouble for others?

@daniilS
Copy link
Contributor Author

daniilS commented Jan 7, 2022

@richardsheridan thanks for your feedback! I agree that a note is definitely needed somewhere.

I was unsure initially about how much other embedded users rely on the current behaviour, as it's undocumented, different from what's expected from any other widget, and existing code should still work after the patch if an end user clicks the plot (which I was doing myself before I realised the canvas claimed the focus for itself). If we do go with a deprecation period, we should probably still add the focus_set() call in show() straight away, as an immediate fix for #22028. get_tk_widget() might be the best place to put a warning about the change.

@ebardie
Copy link

ebardie commented Jan 18, 2022

This fixes #22255, and https://gitlab.com/eBardie/topplot/-/issues/46. Thanks @daniilS.

@tacaswell tacaswell modified the milestones: v3.5.2, v3.6.0 Jan 18, 2022
@daniilS
Copy link
Contributor Author

daniilS commented Jan 22, 2022

I've removed the backward-incompatible change that prevented the tk canvas from stealing the focus upon creation, and will submit a separate PR for that with proper deprecation, aimed at 3.6.0. For now, this just closes #22028, #13484, #22255, and this issue on Discourse. As it's just a fix now, I would propose it get included in 3.5.2.

Copy link
Contributor

@richardsheridan richardsheridan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@richardsheridan richardsheridan added PR: bugfix Pull requests that fix identified bugs and removed status: needs workflow approval For PRs from new contributors, from which GitHub blocks workflows by default. labels Jan 24, 2022
@richardsheridan richardsheridan modified the milestones: v3.6.0, v3.5.2 Jan 24, 2022
@daniilS
Copy link
Contributor Author

daniilS commented Jan 25, 2022

@timhoffm thanks, think #22028 and #22255 can be closed now!

QuLogic added a commit that referenced this pull request Jan 27, 2022
…077-on-v3.5.x

Backport PR #22077 on branch v3.5.x (Fix keyboard event routing in Tk backend (fixes #13484, #14081, and #22028))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
GUI: tk PR: bugfix Pull requests that fix identified bugs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants