2

Is there any way to find a widget's parent (specifically button) without saving the parent in an object attribute?

but = Button(main_window, text = "close window!")
but.bind("<Button-1>", btn_handler)

def btn_handler(e):
    e.parent().destroy() # I need something like this!
    # e.parent() ==>> main_window
    # without writing class and defining self.parent ...

I am searching internet for several hours and I didn't find proper answer.

Milad R
  • 1,854
  • 9
  • 25
  • 36
  • 1
    You can use lambda or you can use global variables. But class solution is usually the best. – Eric Levieil Jun 20 '15 at 15:40
  • @iCodez But unless I'm just ignorant, the `command` callback isn't given the event that calls it so you don't have a reference to the button that's being clicked inside the function. (Unless you explicitly pass it e.g. `but = Button(main_window, text="close window!"); but.configure(command=lambda: btn_handler(but))` – Adam Smith Jun 20 '15 at 15:50
  • @EricLevieil would you please give link/explanation/something about "lambda"? – Milad R Jun 20 '15 at 15:52
  • 1
    @MiladR `lambda` functions are anonymous functions. You'll need a tutorial, but essentially `foo = lambda num: num*2` is the same as `def foo(num): return num*2`. There's no good reason to ever NAME a lambda like I did there (by assigning it to `foo`), but they're good for one-shot functions like callbacks. – Adam Smith Jun 20 '15 at 15:53
  • 1
    @AdamSmith - Ah, my mistake. I've seen people bind buttons incorrectly so many times, I thought this was just another occurrence. But in this case, it is actually necessary. Sorry for the confusion. :) –  Jun 20 '15 at 15:56

1 Answers1

8

You can use but.master to access the parent of the but object.

To get the container widget of a widget that's handling a callback, you can do:

def callback(evt):
    handling_widget = evt.widget
    parent_of_handling_widget = handling_widget.master
    # or evt.widget.master
    parent_of_handling_widget.destroy()

That said, I'm not exactly sure why you're trying to avoid using a custom class. It's a natural solution to your problem.

import tkinter
from tkinter import ttk

class MyButton(ttk.Button):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.configure(command=self.callback)

    def callback(self):
        self.master.destroy()

tk = tkinter.Tk()
b = MyButton(tk, text="close window!")
b.pack()  # or whatever geometry manager you're using

# we're done!
Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • 2
    e.widget.master is probably more what OP wants. – Eric Levieil Jun 20 '15 at 15:43
  • @EricLevieil ah, true. I wasn't really taking the intended use as context, but should have. I'll edit. – Adam Smith Jun 20 '15 at 15:44
  • @AdamSmith Thanks! I have a miscellaneous question! I know a little thing about "super" method, that you can use in order to call parent function. But I haven't seen ' **something ' in python. Is it some kind of pointer such as C++ pointers? What is it? What's the name of its subject? – Milad R Jun 20 '15 at 16:31
  • 1
    @MiladR no, they're completely unrelated. See [this canonical post](http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters) – Adam Smith Jun 20 '15 at 16:54