Calling functions from a Tkinter Frame to another
I have a page where I'll show some customers details. So I created a page called "customers details" with all the labels that I need and I set the text of these labels as variables. Too bad it doesn't work. The labels are created in the __init__
method so I can't "update" them, becouse the init is called only at the beginning. So what I thought is to create a new function that contains all the labels and I will call that function when I have the necessity...here's the problem. I'm not able to call a function in an other tk.Frame
. The following code is a simplified version of the code.
import tkinter as tk
from tkinter import ttk
class Myapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = ttk.Frame(self, borderwidth=10, relief="sunken", width=200, height=100)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (HomePage, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="N,S,E,W")
self.show_frame(HomePage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text="HomePage")
label.pack()
button1 = ttk.Button(self, text="Quit",
command=lambda: quit())
button1.pack()
button2 = ttk.Button(self, text="Call Function in the other page/class to show the label",
command=lambda: PageOne.function()) # this is to do it from an other class. I can't do this
button2.pack()
button3 = ttk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button3.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text="PageOne")
label.pack()
button1 = ttk.Button(self, text="Quit",
command=lambda: quit())
button1.pack()
button2 = ttk.Button(self, text="Call Function, in local it works..",
command=lambda: self.function())#this is to do it in local
button2.pack()
button3 = ttk.Button(self, text="HomePage",
command=lambda: controller.show_frame(HomePage))
button3.pack()
def function(self):
label1 = ttk.Label(self, text="It Worked!")
label1.pack()
app = Myapp()
app.mainloop()
To call a method on another object, you need a reference to the object. The code you copied for managing the different pages is designed to make this easy, but it is missing a function to get the instance of a page.
So, the first think you need to do is add a get_page
method on the controller:
class Myapp(tk.Tk):
...
def get_page(self, page_class):
return self.frames[page_class]
With that, you can get the page instance, and with the page instance you can call the method.
Next, you need to keep a reference to the controller so that you can call it from other functions:
class PageOne(tk.Frame):
def __init__(self, parent, controller):
self.controller = controller
...
Finally, you can now use the controller to get the page, and with the page you can call the function.
My recommendation is to not use lambda
unless you absolutely need it, and in this case you do not. It's much easier to write and debug your code when you use proper functions instead of lambda
.
For example:
class PageOne(tk.Frame):
def __init__(self, parent, controller):
...
button2 = ttk.Button(..., command=self.do_button)
...
def do_button(self):
page = self.controller.get_page(PageOne)
page.function()