Tkinter: How to pass a StringVar to another class? - python

I have two tkinter Frames through which I'm trying to pass values to determine which button was pressed. Here is what I have:
class GUIHandler(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frames = {}
for F in (MainFrame, GraphsTask):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(MainFrame)
class MainFrame(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.button_text = tk.StringVar()
tk.Button(self, text="Task 2a",
command=lambda: self.button_controller(GraphsTask, 'task_2a'))
def button_controller(self, class_name, btn_text):
self.controller.show_frame(class_name)
self.button_text.set(btn_text)
def get_button_text(self):
print(self.button_text.get())
return self.button_text.get()
class GraphsTask(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.bind("<<Show>>", self.get_graph)
def get_graph(self, event):
if self.controller.frames[MainFrame].get_button_text() == 'task_2a':
....
When I try to compare the result I get from get_button_text() function from MainFrame class, it returns empty even though the print statement inside that function prints the text I passed onto button_controller() function. I do not understand what is going on here.

You should update self.button_text first and then switch page:
def button_controller(self, class_name, btn_text):
self.button_text.set(btn_text)
self.controller.show_frame(class_name)

Related

Get variable from parent using container class

I have Tkinter main class with a notebook:
class MainApplication(tk.Tk):
def __init__(self):
super().__init__()
self.color_widget = '#1B608E'
self.notebook = ttk.Notebook(self)
self.Page1 = Page1(self.notebook)
self.Page2 = Page2(self.notebook)
self.notebook.add(self.Page1, text='PCE Franchisés')
self.notebook.add(self.Page2, text='PVC Franchisés')
For each page of the notebook, I have a class defined as container:
class Page1(ttk.Frame):
def __init__(self, container):
super().__init__(container)
color = MainApplication.color_widget
self.label_INPUT = tk.Label(self, text='Settings', color=color,
)
self.label_INPUT.place(relx=0.03, rely=0.04)
class Page2(ttk.Frame):
def __init__(self, container):
super().__init__(container)
In each Page I want get the value of the variale color_widget defined in Main class. I tried MainApplication.color_widegt but it didn't work.
The simple way is to pass the instance of MainApplication to those pages, so that those pages can access the instance variable color_widget via the passed instance:
import tkinter as tk
from tkinter import ttk
class MainApplication(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('800x600')
self.color_widget = '#1B608E'
self.notebook = ttk.Notebook(self)
self.notebook.pack(fill='both', expand=1)
self.Page1 = Page1(self.notebook, self) # pass instance of MainApplication as well
self.Page2 = Page2(self.notebook, self)
self.notebook.add(self.Page1, text='PCE Franchisés')
self.notebook.add(self.Page2, text='PVC Franchisés')
class Page1(ttk.Frame):
# added controller argument
def __init__(self, container, controller):
super().__init__(container)
self.controller = controller
# access MainApplication.color_widget
color = controller.color_widget
self.label_INPUT = tk.Label(self, text='Settings', fg=color)
self.label_INPUT.place(relx=0.03, rely=0.04, anchor='nw')
class Page2(ttk.Frame):
def __init__(self, container, controller):
super().__init__(container)
self.controller = controller
MainApplication().mainloop()

I am using class based tkinter to change frame and navigate now how could I exchange data between those classes [duplicate]

This question already has answers here:
How to access variables from different classes in tkinter?
(2 answers)
Closed 1 year ago.
I have two classes(frames) for Tkinter one class generates a user id variable by using api inside a bbutton command method now i want to use that into another class how can i do it i have defined that variable global but not working.
my code is something like this
class login page(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def button_function():
global user_id
user_id = some value i got from api response
button = tk.button(command = button_fucntion())
class destination_page(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def another_button_function(user_id):
#i want that user_id value here
button_2 = tk.button(command = another_button_fucntion(user_id))
This code is able to access user_id and print it.
Buttons must be pressed in the correct order to prevent an error so this is a problem that needs to be addressed.
I've simplified it since I have no idea what controller does.
import tkinter as tk
class login_page(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def button_function():
global user_id
user_id = "some value i got from api response"
#
self.button = tk.Button(
self, text = "Click me first", command = button_function)
self.button.grid(sticky = tk.NSEW)
class destination_page(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def another_button_function(user_id):
print(user_id) #i want that user_id value here
#
self.button_2 = tk.Button(
self, text = "Click me second",
command = lambda: another_button_function(user_id))
self.button_2.grid(sticky = tk.NSEW)
master = tk.Tk()
app1 = login_page(master, "?")
app1.grid(sticky=tk.NSEW)
app2 = destination_page(master, "?")
app2.grid(sticky=tk.NSEW)
master.mainloop()

Problem with Tkinter - Inheritance problems

I'm starting to work with classes with a Tkinter app, but I don't seem to understand how classes work, especially the relationship parent-controller. As you can see in the code down below, I was planning to have an outer class for a whole section, then 4 inner classes for every section within that frame. However, I cannot call those classes from the initial frame. Is there any better way to do this? What is it that I'm doing wrong?
class MainScreenFrameCenter(tk.Frame):
def __init__(self, parent, controller,*args,**kwargs):
tk.Frame.__init__(self,parent, bg="white",height=680, width=640,highlightbackground="black", highlightthickness=1)
self.controller = controller
self.pack(side="top", fill="both", expand=True)
self.widgets_nw = MainScreenFrameCenterNW(parent=self,controller=self)
self.widgets_sw = MainScreenFrameCenterSW(parent=self,controller=self)
self.widgets_ne = MainScreenFrameCenterNE(parent=self,controller=self)
self.widgets_se = MainScreenFrameCenterSE(parent=self,controller=self)
class MainScreenFrameCenterNW(tk.Frame):
def __init__(self, parent, controller,*args,**kwargs):
tk.Frame.__init__(self,parent,height=350,width=640,bg="white",highlightbackground="black",highlightthickness=1)
self.controller = controller
self.grid(row=0,column=0,sticky="nsew")
class MainScreenFrameCenterSW(tk.Frame):
def __init__(self, parent, controller,*args,**kwargs):
tk.Frame.__init__(self,parent,height=350,width=640,bg="white",highlightbackground="black",highlightthickness=1)
self.controller = controller
self.grid(row=1,column=0,sticky="nsew")
class MainScreenFrameCenterNE(tk.Frame):
def __init__(self, parent, controller,*args,**kwargs):
tk.Frame.__init__(self,parent,height=350,width=640,bg="white",highlightbackground="black",highlightthickness=1)
self.controller = controller
self.grid(row=0,column=1,sticky="nsew")
class MainScreenFrameCenterSE(tk.Frame):
def __init__(self, parent, controller,*args,**kwargs):
tk.Frame.__init__(self,parent,height=350,width=640,bg="white",highlightbackground="black",highlightthickness=1)
self.controller = controller
self.grid(row=1,column=1,sticky="nsew")
You need to move all of the class definitions to global scope by putting them all at the same level of indentation.
class MainScreenFrameCenter(tk.Frame):
...
class MainScreenFrameCenterNW(tk.Frame):
...
class MainScreenFrameCenterSW(tk.Frame):
...
class MainScreenFrameCenterNE(tk.Frame):
...
class MainScreenFrameCenterSE(tk.Frame):
...
It seems you are attempting to make a small grid. Classes are generally not nested inside of another class. If you create a class that represents 1 grid cell, you can use a loop to create a grid from it.
import tkinter as tk
class Cell(tk.Frame):
def __init__(self, master, column:int=0, row:int=0, **kwargs):
kwargs = {**{'bg':'white', 'highlightbackground':'black','highlightthickness':1}, **kwargs}
tk.Frame.__init__(self, master, **kwargs)
self.grid(column=column, row=row, sticky='nswe')
class App(tk.Tk):
def __init__(self, **kwargs):
tk.Tk.__init__(self)
self.configure(**kwargs)
cols = 2
for i in range(cols):
self.grid_columnconfigure(i, weight=1)
rows = 2
for i in range(rows):
self.grid_rowconfigure(i, weight=1)
for i, c in enumerate(['nw', 'ne', 'sw', 'se']):
self.__dict__[f'widgets_{c}'] = Cell(self, i%cols, i//cols)
self.widgets_nw['background'] = 'red'
if __name__ == '__main__':
root = App(background="white", highlightbackground="black", highlightthickness=1)
root.geometry('640x680+300+300')
root.title('not Can is Should Example')
root.mainloop()

I keep getting this AttributeError: '_tkinter.tkapp' object has no attribute 'TK'

I've been doing a Gui multiple windows quest but Tkinter doesn't seem to have Tk. My full error is
Traceback (most recent call last):
File "/Users/connorsmacbook/PycharmProjects/2.8/2.8 Internal/TextTypers 2.2.py", line 6, in <module>
class TextTypers(tk.TK):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 2101, in __getattr__
return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'TK'
My code is
from tkinter import *
tk=Tk()
# Classes
class TextTypers(tk.TK):
def __init__(self, *args, **kwargs): # Runs when our class is called and allows almost anything to be passed
tk.Tk.__init__(self, *args, **kwargs) # Initialise Tk
window = tk.Frame(self) # Creates the container the windows/frames will populate
window.pack()
self.frames = {} # Creates a dictionary for the frames
frame = MenuScreen(window, self)
self.frames[MenuScreen] = frame
frame.grid(row=0, column=0, sticky="nswe")
self.show_frame(MenuScreen) # Shows the menu screen as this is initialising
def show_frame(self, cont):
frame = self.frames[cont] # Grabs value of self.frames and puts in in frame
frame.tkraise() # Raises frame to the front
class MenuScreen(tk.frame): # Inherits everything from the frame
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent) # Inherits from main class
label = tk.Label(self, text="Menu")
label.pack()
run = TextTypers()
run.mainloop()
If any wizards could help I would be grateful :).
The line
tk=Tk()
creates an instance of Tk() with the name tk.
When you create the class
class TextTypers(tk.TK):
you are trying to inherit an attribute called TK from the instance tk.
In general, I would not use the name tk for the root window as tk is usually used as an alias for the tkinter module.
I think what you are after is something like this:
import tkinter as tk
# Classes
class TextTypers(tk.Tk):
def __init__(self, *args, **kwargs): # Runs when our class is called and allows almost anything to be passed
tk.Tk.__init__(self, *args, **kwargs) # Initialise Tk
window = tk.Frame(self) # Creates the container the windows/frames will populate
window.pack()
self.frames = {} # Creates a dictionary for the frames
frame = MenuScreen(window, self)
self.frames[MenuScreen] = frame
frame.grid(row=0, column=0, sticky="nswe")
self.show_frame(MenuScreen) # Shows the menu screen as this is initialising
def show_frame(self, cont):
frame = self.frames[cont] # Grabs value of self.frames and puts in in frame
frame.tkraise() # Raises frame to the front
class MenuScreen(tk.Frame): # Inherits everything from the frame
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent) # Inherits from main class
label = tk.Label(self, text="Menu")
label.pack()
run = TextTypers()
run.mainloop()
Have a look at Best way to structure a tkinter application were you can find some suggestions and discussion.

How to get a variable from a parameter function outside his class?

I'm creating an GUI interface for my own project in python with tkinter library.
On one frame i setted an tk.Entry for me to write some text.
I want to use this information in the next Frame (let's say in a tk.Label to be simple)
But i can't reach the information, seems to be because the two function belong to differents class.
Tried to make private_key global but seems to overwrite in the definition.
Tried to return private_key but i still can't access it because i can't call the parameter in the next class.
Tried to use the function again in the next class, same problem.
Tried to set the label in the PVK class, doesn't seems to work either
from tkinter import *
# type and size of font
LARGE_FONT = ('MS Serif', 15)
# white writing color
FRONT_COLOR = '#ffffff'
# dark_gray background color
BACKGROUND_COLOR = '#272727'
class Bobby(Tk):
# Used each time the function is called
def __init__(self):
# init tkinter
Tk.__init__(self)
Tk.iconbitmap(self, default='bobby.ico')
Tk.wm_title(self, "Bobby")
Tk.geometry(self, '500x200')
container = Frame(self)
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 (PVK, Display):
frame = f(container, self)
self.frames[f] = frame
frame.grid(row=0, column=0, sticky=NSEW)
self.show_frame(Welcome)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class PVK(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.configure(background=BACKGROUND_COLOR)
here = Label(self, text="here", font=LARGE_FONT, background=BACKGROUND_COLOR, fg=FRONT_COLOR)
here.grid()
self.pvk = Entry(self, show=" ")
self.pvk.bind('<Return>', self.check)
self.pvk.grid()
def check(self, event):
private_key = int(self.pvk.get()), 11413
bobby.show_frame(Display)
return private_key
class Display(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.configure(background=BACKGROUND_COLOR)
#want to display it here
Label(self, text=str(PVK.private_key)).grid()
bobby = Bobby()
bobby.mainloop()
My expect is to display the label with the text in it which would mean i can use the variable.
I currently get the error that private_key isn't defined.
Since you pass controller into the __init__() of Display, then you could find the instance of the PVK class:
class PVK(Frame):
def __init__(self, parent, controller):
# stuff omitted
def check(self, event):
self.private_key = int(self.pvk.get()), 11413 # note self.private_key
bobby.show_frame(Display)
class Display(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.configure(background=BACKGROUND_COLOR)
#want to display it here
private_key = controller.frames[PVK].private_key
Label(self, text=str(private_key)).grid()
There will be other ways to access private_key, eg PVK could write it back to the controller: self.controller.private_key = private_key etc

Categories

Resources