Skip to content

NavigationToolbar2Tk: make packing optional. #15274

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 2 commits into from
Oct 2, 2019

Conversation

jmehne
Copy link
Contributor

@jmehne jmehne commented Sep 16, 2019

PR Summary

Currently, NavigationToolbar2Tk cannot be easily used with the grid layout manager.
When initalizing the toolbar, it is immediately packed: self.pack(side=tk.BOTTOM, fill=tk.X)

I think this is unfortunate behavior, because:

  • It is unexpected.
    Usually, you initialize a widget and afterwards it must be added to one of the layout managers.
  • It makes it hard to use the toolbar with the grid layout manager.
    You need to call pack_forget() on the toolbar first, before you can add it to the grid layout manager.
  • When resizing a window that contains the canvas and the toolbar in the same frame: how do you make sure, that the toolbar is not resized first and thus disappears before the canvas widget?
    You need to initialize it before the canvas, which again, is not super obvious.
    But then, how do you place the toolbar on top of the canvas - it is packed with side=tk.BOTTOM, so basically you have to call pack_forget and repack it with side=tk.TOP.
    Or, you initialize the canvas before the toolbar, but then you get the resizing problem again.

I assume we cannot change the default behavior for backwards compatibility, so this PR makes packing optional.

No idea how to write a test for this. Couldn't get the tests to run locally on master, so I'm relying on the CI tests.

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

If True, add the toolbar to the parent's pack manager's packing list
during initialization with *side='bottom'* and *fill='x'*.
If you want to use the toolbar with a different layout manager, you
must first call *pack_forget* on the toolbar object.

Choose a reason for hiding this comment

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

I was confused by this sentence when first reading it, After all, the change proposed here is meant to prevent the need to call pack_forget. Maybe move it to the bottom and let it say

If you want to use the toolbar with a different layout manager, use pack_toolbar=False.

@jmehne jmehne force-pushed the tk-toolbar-grid branch 3 times, most recently from 60a4243 to 4910587 Compare September 16, 2019 20:26
@jmehne
Copy link
Contributor Author

jmehne commented Sep 16, 2019

I changed the sentence accordingly.

I also changed the "Embedding in Tk" example again to use the new parameter, because I believe it is usually the better option:

  • If you want to use pack, it is now easier to infer from the example how to place the toolbar at the top.
  • If you don't want to use pack, it should just work.
  • Explicit is better than implicit :)

Copy link
Member

@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

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

Thanks, this looks good modulo some minor documentation.

@jmehne
Copy link
Contributor Author

jmehne commented Sep 17, 2019

Thanks for the reviews! I changed the docstring accordingly.

@jmehne
Copy link
Contributor Author

jmehne commented Sep 17, 2019

Hm, please don't merge this yet. In the example the toolbar height gets suddenly resized. Will take a look later today.

"""
def __init__(self, canvas, window):
def __init__(self, canvas, window, pack_toolbar=True):
Copy link
Contributor

Choose a reason for hiding this comment

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

please make the argument keyword only

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After some googling the signature is now:

def __init__(self, canvas, window, *, pack_toolbar=True):

I didn't know this was possible at all, so please correct me if there is a more canonical way to do it.

@jmehne
Copy link
Contributor Author

jmehne commented Sep 17, 2019

Okay, I fixed the example. I used expand=True for the toolbar in the example which didn't make sense.
Looks good now:

tkinter_test

self.canvas = canvas
# Avoid using self.window (prefer self.canvas.get_tk_widget().master),
# so that Tool implementations can reuse the methods.
self.window = window
self.pack_toolbar = pack_toolbar
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't need to be a public attribute -- it's just there for coordination between __init__ and _init_toolbar -- which gets called by __init__ anyways.
In fact you could even move the call to pack out of _init_toolbar and put it here:

if pack_toolbar: self.pack(...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I moved the call.

@anntzer
Copy link
Contributor

anntzer commented Sep 17, 2019

I agree that the old behavior looked strange (well, at least from a qt PoV; dunno what's standard with tk...); if you think we should ultimately switch the default to not packing, see e.g. the deprecation strategy used in #12380

Currently, the toolbar cannot be easily used with Tk's grid layout
manager, because it is already packed during initialization. Thus, it is
necessary to manually call `pack_forget` on the toolbar.

Add a parameter, that makes this a bit easier to discover.
@jmehne
Copy link
Contributor Author

jmehne commented Sep 17, 2019

I'm not really a Tkinter expert, so I don't feel like I can decide at the moment if the default behavior should ultimately be switched or not. My gut feeling says yes, but there is no urgency to switch so I think it's a good idea to just introduce the change and let it sit for a bit.

Copy link
Contributor

@anntzer anntzer left a comment

Choose a reason for hiding this comment

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

lgtm, just tiny formatting things

@jmehne
Copy link
Contributor Author

jmehne commented Sep 17, 2019

Docstring updated to use double backticks.

@timhoffm timhoffm added this to the v3.3.0 milestone Oct 2, 2019
@timhoffm timhoffm merged commit f49b7d1 into matplotlib:master Oct 2, 2019
@timhoffm
Copy link
Member

timhoffm commented Oct 2, 2019

Thanks!

@jmehne jmehne deleted the tk-toolbar-grid branch October 3, 2019 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants