Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 tkinter button command inside different class

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!

like image 664
jacobian Avatar asked Jun 07 '15 05:06

jacobian


People also ask

Can Tkinter buttons have multiple commands?

We can perform a certain action with the help of a Button that encapsulates the function and the objects. However, there might be cases when we want to perform multiple operations with a single button. This can be achieved by defining the lambda functions which target multiple events or callback in the application.

Can you have two commands Tkinter?

The Tkinter button has only one command property so that multiple commands or functions should be wrapped to one function that is bound to this command .

What is __ init __ In Tkinter?

"__init__" is a reseved method in python classes. It is called as a constructor in object oriented terminology. This method is called when an object is created from a class and it allows the class to initialize the attributes of the class.


1 Answers

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()
like image 55
TigerhawkT3 Avatar answered Oct 03 '22 14:10

TigerhawkT3