From 843542d6f81a1f0eabe801aea6fc06ee25edefea Mon Sep 17 00:00:00 2001 From: Pranav Date: Sat, 13 Dec 2025 22:00:52 +0530 Subject: [PATCH] Added API note, enhanced gallery example, applied fix Co-authored-by: daniilS --- .../next_api_changes/behavior/30852-PR.rst | 10 ++++ .../user_interfaces/embedding_in_tk_sgskip.py | 3 ++ lib/matplotlib/backends/_backend_tk.py | 2 - lib/matplotlib/tests/test_backend_tk.py | 53 ++++++++++++------- 4 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 doc/api/next_api_changes/behavior/30852-PR.rst diff --git a/doc/api/next_api_changes/behavior/30852-PR.rst b/doc/api/next_api_changes/behavior/30852-PR.rst new file mode 100644 index 000000000000..1e2bf2801df7 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30852-PR.rst @@ -0,0 +1,10 @@ +Default focus behavior of ``FigureCanvasTkAgg`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, when a `.FigureCanvasTkAgg` object was created, focus was set to the +canvas by default. Now, focus is not set anymore. If focus is desired on the canvas, +it can be set explicitly after creation using the ``focus_set()`` method of Tkinter +widgets. + +See :doc:`../../../gallery/user_interfaces/embedding_in_tk_sgskip` for an example of +focus-setting in an embedded Matplotlib figure in a Tkinter application. diff --git a/galleries/examples/user_interfaces/embedding_in_tk_sgskip.py b/galleries/examples/user_interfaces/embedding_in_tk_sgskip.py index 2fa132a80227..e77dda1742b2 100644 --- a/galleries/examples/user_interfaces/embedding_in_tk_sgskip.py +++ b/galleries/examples/user_interfaces/embedding_in_tk_sgskip.py @@ -62,4 +62,7 @@ def update_frequency(new_val): toolbar.pack(side=tkinter.BOTTOM, fill=tkinter.X) canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=True) +# Explicitly set focus to canvas for it to receive key press events +canvas.get_tk_widget().focus_set() + tkinter.mainloop() diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index 42782b2f00e1..1c5bb6ab0d24 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -255,8 +255,6 @@ def filter_destroy(event): CloseEvent("close_event", self)._process() filter_destroy_id = root.bind("", filter_destroy, "+") - self._tkcanvas.focus_set() - self._rubberband_rect_black = None self._rubberband_rect_white = None diff --git a/lib/matplotlib/tests/test_backend_tk.py b/lib/matplotlib/tests/test_backend_tk.py index 1f96ad1308cb..ee35406aa048 100644 --- a/lib/matplotlib/tests/test_backend_tk.py +++ b/lib/matplotlib/tests/test_backend_tk.py @@ -215,33 +215,48 @@ def test_save_figure_return(): print("success") -@_isolated_tk_test(success_count=1) +@_isolated_tk_test(success_count=3) def test_canvas_focus(): + import matplotlib import tkinter as tk import matplotlib.pyplot as plt - success = [] + from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg + matplotlib.use('Tkagg') - def check_focus(): - tkcanvas = fig.canvas.get_tk_widget() - # Give the plot window time to appear - if not tkcanvas.winfo_viewable(): - tkcanvas.wait_visibility() - # Make sure the canvas has the focus, so that it's able to receive - # keyboard events. - if tkcanvas.focus_lastfor() == tkcanvas: - success.append(True) - plt.close() - root.destroy() + def assert_focus(widget, expected_focus_state): + if not widget.winfo_viewable(): + widget.wait_visibility() + + has_focus = (widget.focus_get() == widget) + + if has_focus == expected_focus_state: + print("success") root = tk.Tk() fig = plt.figure() - plt.plot([1, 2, 3]) - root.after(0, plt.show) - root.after(100, check_focus) - root.mainloop() + canvas = FigureCanvasTkAgg(fig, root) + tkcanvas = canvas.get_tk_widget() + tkcanvas.pack() - if success: - print("success") + # Test 1: Default Behavior (No Focus Stealing) + assert_focus(tkcanvas, expected_focus_state=False) + + # Test 2: Explicit Focus + tkcanvas.focus_force() + assert_focus(tkcanvas, expected_focus_state=True) + + plt.close(fig) + root.destroy() + + # Test 3: Showing the plot should grab focus + fig2 = plt.figure() + tkcanvas2 = fig2.canvas.get_tk_widget() + + plt.show(block=False) + + assert_focus(tkcanvas2, expected_focus_state=True) + + plt.close(fig2) @_isolated_tk_test(success_count=2)