Skip to content
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

Place, Pack and Grid should return the widget #79881

Closed
Epyxoid mannequin opened this issue Jan 9, 2019 · 7 comments
Closed

Place, Pack and Grid should return the widget #79881

Epyxoid mannequin opened this issue Jan 9, 2019 · 7 comments
Labels
3.8 only security fixes topic-tkinter type-feature A feature request or enhancement

Comments

@Epyxoid
Copy link
Mannequin

Epyxoid mannequin commented Jan 9, 2019

BPO 35700
Nosy @terryjreedy, @zware, @serhiy-storchaka, @MojoVampire, @Epyxoid
PRs
  • bpo-35700: Added a much-needed functionality to Place, Pack and Grid #11475
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2019-01-09.17:47:24.599>
    created_at = <Date 2019-01-09.13:31:37.371>
    labels = ['3.8', 'type-feature', 'expert-tkinter']
    title = 'Place, Pack and Grid should return the widget'
    updated_at = <Date 2019-01-09.19:20:42.300>
    user = 'https://github.com/Epyxoid'

    bugs.python.org fields:

    activity = <Date 2019-01-09.19:20:42.300>
    actor = 'terry.reedy'
    assignee = 'none'
    closed = True
    closed_date = <Date 2019-01-09.17:47:24.599>
    closer = 'josh.r'
    components = ['Tkinter']
    creation = <Date 2019-01-09.13:31:37.371>
    creator = 'Epyxoid'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 35700
    keywords = []
    message_count = 7.0
    messages = ['333318', '333323', '333324', '333332', '333337', '333339', '333343']
    nosy_count = 6.0
    nosy_names = ['terry.reedy', 'gpolo', 'zach.ware', 'serhiy.storchaka', 'josh.r', 'Epyxoid']
    pr_nums = ['11475']
    priority = 'normal'
    resolution = 'rejected'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue35700'
    versions = ['Python 3.8']

    @Epyxoid
    Copy link
    Mannequin Author

    Epyxoid mannequin commented Jan 9, 2019

    When you want to simply place a widget on a window and you also want to store the reference for that widget in a variable you can't do that in one line, which is really unpleasant, because when you create a new widget these things are usually the first what you want to do with a widget and breaking it two line is just making things more complicated.

    For example, if you want to create 3 label, place it next to each other and store their reference:

    import tkinter as tk
    root = tk.Tk()
    
    # you can't do that:
    # here the variables assigned to None, since grid() returns 'nothing'
    label1 = tk.Label(root).grid(row=0, column=0)
    label2 = tk.Label(root).grid(row=0, column=1)
    label3 = tk.Label(root).grid(row=0, column=2)
    
    # actually, you must do this:
    label1 = tk.Label(root)
    label1.grid(row=0, column=0)
    label2 = tk.Label(root)
    label2.grid(row=0, column=1)
    label3 = tk.Label(root)
    label3.grid(row=0, column=2)

    @Epyxoid Epyxoid mannequin added type-bug An unexpected behavior, bug, or error 3.7 (EOL) end of life topic-tkinter labels Jan 9, 2019
    @serhiy-storchaka
    Copy link
    Member

    Methods place(), pack() and grid() correspond to corresponding Tk commands. These commands return nothing (empty string) in Tk, and Tkinter methods return nothing (None) in Python. If they will became returning something meaningful in future versions of Tk, we will lost a chance to translate this to Python if make them now returning the widget itself.

    Note also that method chaining is not commonly used in Python. This code would look pretty unpythonic.

    For these reasons I am against this idea.

    @Epyxoid
    Copy link
    Mannequin Author

    Epyxoid mannequin commented Jan 9, 2019

    I can somewhat agreed with your point, even if it's not too realistic, but reasonable enough.

    Also, I'd only use method chaining, because that'd be the only option. I can't pass an argument to tk.Label at creation like 'manager="grid"' or anything like that. In any case, I think doing it in a separate line makes the code longer and less readable even if it's pythonic.

    Thanks for your consideration.

    @zware
    Copy link
    Member

    zware commented Jan 9, 2019

    I agree with Serhiy that we shouldn't do this; tkinter is (mostly) just a thin wrapper around Tcl/Tk and this isn't enough of a win to deviate from that. In any case, this would be an enhancement that could only go into 3.8 at this point.

    For your particular example, it would prefer to read the following anyway:

    import tkinter as tk
    
    root = tk.Tk()
    
    labels = []
    for i in range(3):
        label = tk.Label(root)
        label.grid(row=0, column=i)
        labels.append(label)
    

    Or if you really want this feature in your own code, try this out:

    import tkinter as tk
    from functools import partial
    
    def _mapped(method, widget, *args, **kwargs):
        getattr(widget, method)(*args, **kwargs)
        return widget
    
    packed = partial(_mapped, 'pack')
    gridded = partial(_mapped, 'grid')
    placed = partial(_mapped, 'place')
    
    root = tk.Tk()
    
    label1 = gridded(tk.Label(root), row=0, column=0)
    label2 = gridded(tk.Label(root), row=0, column=1)
    label3 = gridded(tk.Label(root), row=0, column=2)
    

    @zware zware added 3.8 only security fixes type-feature A feature request or enhancement and removed 3.7 (EOL) end of life type-bug An unexpected behavior, bug, or error labels Jan 9, 2019
    @Epyxoid
    Copy link
    Mannequin Author

    Epyxoid mannequin commented Jan 9, 2019

    Thank you Zachary, very interesting examples, to say the least!

    @Epyxoid Epyxoid mannequin added 3.7 (EOL) end of life type-bug An unexpected behavior, bug, or error and removed 3.8 only security fixes type-feature A feature request or enhancement labels Jan 9, 2019
    @zware zware added 3.8 only security fixes type-feature A feature request or enhancement and removed 3.7 (EOL) end of life type-bug An unexpected behavior, bug, or error labels Jan 9, 2019
    @MojoVampire
    Copy link
    Mannequin

    MojoVampire mannequin commented Jan 9, 2019

    Closing as rejected; to my knowledge, *no* built-in Python method both mutate an object and returns the object just mutated, precisely because:

    1. It allows for chaining that leads fairly quickly to unreadable code (Python is not Perl/Ruby)

    2. It creates doubt as to whether the original object was mutated or not (if list.sort returns a sorted list, it becomes unclear as to whether the original list was sorted as well, or whether a new list was returned; sortedlist = unsortedlist.sort() might give an inaccurate impression of what was going on). Zachary's example of using top-level functions to do the work instead is basically the same practicality compromise that sorted makes in relation to list.sort.

    @MojoVampire MojoVampire mannequin closed this as completed Jan 9, 2019
    @terryjreedy
    Copy link
    Member

    1. (Josh beat me here.) One of Python's design features is that stdlib functions/methods that mutate (or register) an object never (as far as I can remember) return the object. (If they return anything other than None, it is something other than the object. List.pop returns a member, not the list.) Changing this rule either in particular cases or in general has been rejected by Guido multiple times. A new proposal for particular exceptions would have to be approved by the still-in-the-future new design decision process. It would likely start with posting to python-ideas list.

    Consistency of this rule is a feature. If people got used to writing 'item = Widget(...).geo_manager(...)', they would more often make the mistake of writing buggy code like 'items = lister().sort()'

    1. (Based on experience with IDLE.) The toy example with 3 one-line statements creating 3 blank Labels admittedly looks nice and neat. And in such situations, can actually get close today.
    label1 = tk.Label(root); label1.grid(row=0, column=0)
    label2 = tk.Label(root); label2.grid(row=0, column=1)
    label3 = tk.Label(root); label3.grid(row=0, column=2)

    However, in real situations, the widget creation statement is often or usually in the body of a class method and starts with at least an 8 space indent. The call nearly always has a content argument and often other configuration arguments. Such statements often require more than one line even without the manager call added. Manager calls may also have additional arguments. The result is ragged code and if manager calls are appended, they are not so easy to pick out.

    I believe a majority of experienced tkinter users prefer a style omitted from the opening example: create a batch of widgets; then lay them out. The following untested example shows the idea. It keeps the row and column numbers close together and includes parent grid calls in the layout section.

    class Viewframe(Frame):
        def __init__(self, parent, ...)
            ...
            self.populate()
        def populate(self):
            label = Label(self, text='hello world', ...)
            button = Button(self, text='press me), command=lambda: <do something>)
            text = Text(self, ...)
    
            label.grid(row=0, column=0)
            button.grid(row=1, column=0)
            text.grid(row=0, column=1, rowspan=2, sticky='NSEW')
            self.columnconfigure(column=1, weight=1)

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.8 only security fixes topic-tkinter type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants