6

I'm creating a Python (3.4.3) - tkinter program and am wondering whether it is possible to reference a def (self.get_details) from inside another class for a button's command. I haven't been able to find an answer to this problem anywhere, so I figured I'd just ask.

Example:

import tkinter as tk
...

class Widgets(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init___(self, parent)
        self.parent = parent

        self.initUI()

    def initUI():

        # Lots of other different tkinter widgets go here

        self.button = tk.Button(command=App(get_details))
        self.button.pack()


class PopUp(tk.TopLevel): ....

class App(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent

        self.initUI()

    def get_details(self):

        # Complete a function

    def initUI(self):

        self.parent.title("My Application")
        self.style = Style()
        self.style.theme_use("default")

        self.pack()

        self.widgets = Widgets(self)
        self.widgets.pack(side="top", anchor="center", fill="both", expand=True)

if __name__ == "__main__":

    root = tk.Tk()
    App(root).pack(side="top", fill="both", expand=True)
    root.resizable(0,0)
    root.mainloop()

So I would like a button which belongs to the class Widgets() to call a command that is def get_details(self) which belongs to the class App(), which has the Widgets() class packed inside it.

I hope I was descriptive enough, it is fairly hard to word this problem. I am still kind of new to Python in general. Thanks!

Edit:

As suggested I changed it to self.parent.get_details(), which worked! However when I reference a tkinter widget from the Widgets() class inside def get_details() for example: self.button, I get:

AttributeError: 'App' object has no attribute 'button'

So I tried referencing the button as: self.parent.button, to which I received:

AttributeError: 'tkapp' object has no attribute 'button'

How should I be calling/referencing the button? Thanks!

3
  • 1
    self.parent.get_details() should work. Have you tried that? Commented Jun 7, 2015 at 5:40
  • Worked mostly, see edits. Commented Jun 7, 2015 at 6:17
  • To reference something from a Widgets object while you're in get_details, use self.widgets.button. Whichever object you're in, self refers to an instance of that object. Commented Jun 7, 2015 at 6:39

1 Answer 1

2

In App, you create a Widgets object and save a reference to it named self.widgets. When you do so, you pass a reference to that App object into the Widgets object. That App instance reference is saved within the Widgets object as self.parent. Keep in mind that these two uses of self refer to different objects: while in App, self refers to the current instance of that App object. While in Widgets, self refers to the current instance of that Widgets object. To refer to something that's inside the other class, you have to use the proper reference and follow the path.

In an App instance:

self             this App instance
.widgets         the Widgets instance it contains
.button          the button in that Widget instance

In a Widgets instance:

self             this Widgets instance
.parent          the App object that created this Widgets object
.get_details     the get_details function in the parent App object

In the following, I've fixed your code's leftover bits (... causing syntax errors, Style not defined, etc.) and provided a small example of how to reference each object from the other one. The button initially says "hello", which you can change to "goodbye" by clicking it.

import tkinter as tk

class Widgets(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent

        self.initUI()

    def initUI(self):

        # Lots of other different tkinter widgets go here

        self.button = tk.Button(text='hello', command=self.parent.get_details)
        self.button.pack()

class App(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent

        self.initUI()

    def get_details(self):

        self.widgets.button.config(text='goodbye')

    def initUI(self):

        self.parent.title("My Application")

        self.pack()

        self.widgets = Widgets(self)
        self.widgets.pack(side="top", anchor="center", fill="both", expand=True)

if __name__ == "__main__":

    root = tk.Tk()
    App(root).pack(side="top", fill="both", expand=True)
    root.resizable(0,0)
    root.mainloop()
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for explaining that to me so clearly. It's a real help! I tried having the button as self.widgets.button however it still gave me the Attribute Error for 'App' again. I then redefined self.widgets = Widgets(self) directly above where I was trying to call the object, but that gave me a RuntimeError: maximum recursion depth exceeded while calling a Python object. Sorry for being such a pain!
@jimimatthews, I've added a modified version of your code to demonstrate how to reference the various objects.
You've been a great help, Thanks heaps for being so patient, you're a legend!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.