I am using the popular tkinter approach where the original author tried an "pseudo MVC" pattern. Here is the code:
class Main(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.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 (PageOne, PageTwo):
frame = f(container, self)
self.frames[f] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(PageOne)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def get_page(self, page_class):
return self.frames[page_class]
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
def inputs():
r=rq.get('https://swapi.co/api/people/1')
page2 = self.controller.get_page(PageTwo)
page2.resp.set(r.json()['name'])
self.controller.show_frame(PageTwo)
b = tk.Button(station_frame, text="Submit",command=inputs)
b.grid(row=2, column=2, pady=5, padx=5)
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.resp = tk.StringVar()
lbl = tk.Label(self, text=self.resp.get())
lbl.pack(pady=10, padx=10)
while doing this my lbl comes empty and when i set text=self.resp it print PY_VAR0.
Now Here is the part which confuses me. when I change my lbl (Label) with a Button and calls a functions which just prints self.resp.get() it prints the value. Here is the code:
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.resp = tk.StringVar()
def show():
print(self.resp.get())
btm = tk.Button(self, text='call', command=show)
btm.pack(pady=10, padx=10)
I want to show the resp value on a Label on my PageTwo.
Related
I am trying to make a programm where in one frame (window) I have a combobox, then after selecting the combobox value I want it to print a message based on it's value on another window (class), but it says 'int' object has no attribute 'comboBoxDiamUnitString'.
As you will see, I first create the main App, then open up the start page where the combobox is, I select it's value and after some other procees I didn't put in the code as it runs ok I get to the next window, but then I can't use the combobox value in this new class I am in...
What am I missing? Thanks for your help in advance.
class App(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
MainMenu(self)
#Setup Frame
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 (StartPage, PageOne, PageTwo):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, context):
frame = self.frames[context]
frame.tkraise()
class StartPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
def confirmar():
if (self.jobStep >= 0):
respuesta = messagebox.askquestion( self.comboBoxDiamUnitString.get())
if respuesta == "yes":
respuestaInicio = messagebox.askquestion('Puesta en Marcha', 'Iniciar máquina')
if respuestaInicio == "yes":
messagebox.showinfo("Inicio", "Iniciando máquina")
controller.show_frame(PageOne)
self.comboBoxDiamUnitString = tkinter.StringVar()
self.comboBoxDiametro = ttk.Combobox(self, state="readonly", width=5, values=["AWG", "mm"], justify="right", textvariable=self.comboBoxDiamUnitString)
class PageOne(Frame):
def __init__(self, parent, controller):
self.i = 10
GPIO.setmode(GPIO.BOARD)
GPIO.setup(13,GPIO.IN,pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(13, GPIO.FALLING, callback=self.interrupt, bouncetime=300)
def interrupt(self, controller):
if(controller.comboBoxMetroVueltaString.get() == "Vueltas"):
print("vueltas")
if(controller.comboBoxMetroVueltaString.get() == "Metros"):
print("metros")
I have problem with passing dictionary between windows in Tkinter. After successful login I want to create dictionary, in which data of the logged-in user will be stored. I would like dictionary to be available in every window of the program. I tried to do it this way:
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
container = tk.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 (StartPage, Window2, Window1):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.discUserInfo = {}
label = tk.Label(self, text="Start Page", font=controller.title_font)
label.pack()
label2 = tk.Label(self, text="Login:")
label2.pack()
label2.place()
self.e1 = tk.Entry(self)
self.e1.pack()
self.e1.place()
label3 = tk.Label(self, text="Password:")
label3.pack()
label3.place()
self.e2 = tk.Entry(self, show="*")
self.e2.pack()
self.e2.place()
button1 = tk.Button(self, text="Login",
command=self._login_btn_clicked,width = 25)
button1.pack()
button1.place()
def _login_btn_clicked(self):
### after verifying the login data in database, it creates a dictionary with the user's data ( userId,name,lastName ...)
self.discUserInfo['name'] ='Joe'
self.discUserInfo['userId'] =1
self.controller.show_frame("Window1")
class Window2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="window 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Tset",
command=self.onClick, width=42,bg="#C44041")
button1.pack()
button3 = tk.Button(self, text="Back",
command=lambda : controller.show_frame("Window1"), width=42, bg="#C44041")
button3.pack()
def onClick(self):
print (self.discUserInfo)
class Window1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="window 1", font=controller.title_font)
label.pack()
button1 = tk.Button(self, text="Next",
command=lambda: controller.show_frame("Window2"), width=42)
button1.pack()
button1.place()
##################################################
button2 = tk.Button(self, text="Test",
command=self.getAlocationData, width=42)
button2.pack()
button2.place()
def getAlocationData(self):
print(self.discUserInfo)
if __name__ == "__main__":
app = SampleApp()
app.geometry('{}x{}'.format(800, 650))
app.mainloop()
But python shows this error:
print(self.discUserInfo) AttributeError: 'Window1' object has no
attribute 'discUserInfo'.
I tried to create a global dictionary.But working only in some one windows.
If you create the dictionary in the controller (SampleApp) then all other windows could access it via self.controller.discUserInfo. The following is not tested, but something like this may work.
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.discUserInfo = {}
self.frames = {}
for F in (StartPage, Window2, Window1):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Start Page", font=controller.title_font)
label.pack()
label2 = tk.Label(self, text="Login:")
label2.pack()
label2.place()
self.e1 = tk.Entry(self)
self.e1.pack()
self.e1.place()
label3 = tk.Label(self, text="Password:")
label3.pack()
label3.place()
self.e2 = tk.Entry(self, show="*")
self.e2.pack()
self.e2.place()
button1 = tk.Button(self, text="Login",
command=self._login_btn_clicked,width = 25)
button1.pack()
button1.place()
def _login_btn_clicked(self):
### after verifying the login data in database, it creates a dictionary with the user's data ( userId,name,lastName ...)
self.controller.discUserInfo['name'] ='Joe'
self.controller.discUserInfo['userId'] =1
self.controller.show_frame("Window1")
class Window2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="window 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Tset",
command=self.onClick, width=42,bg="#C44041")
button1.pack()
button3 = tk.Button(self, text="Back",
command=lambda : controller.show_frame("Window1"), width=42, bg="#C44041")
button3.pack()
def onClick(self):
print (self.controller.discUserInfo)
class Window1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="window 1", font=controller.title_font)
label.pack()
button1 = tk.Button(self, text="Next",
command=lambda: controller.show_frame("Window2"), width=42)
button1.pack()
button1.place()
##################################################
button2 = tk.Button(self, text="Test",
command=self.getAlocationData, width=42)
button2.pack()
button2.place()
def getAlocationData(self):
print(self.controller.discUserInfo)
if __name__ == "__main__":
app = SampleApp()
app.geometry('{}x{}'.format(800, 650))
app.mainloop()
Launching my program i visualized this error: "module 'tkinter' has no attribute 'Tk'". So I changed the name of my program from "tkinter.py" to "tkinterrr.py" but I obtain that error as well. What can I do?
That's the code:
import tkinter as tk
LARGE_FONT = ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs): #args all var, kwargs all dict
tk.Tk.__init__(self, *args, **kwargs)
container = Tk.Frame(self) #frame hedge window
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
frame = StartPage(container, self)
self.frames[StartPage] = frame
frame.grid(row=0, column=0, sticky="nsew") #you specify all grid
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont] # key
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT) #Label class label object
label.pack(pady=10, padx=10)
app = SeaofBTCapp()
app.mainloop()
Ok I solved... I didn't delete the old "tkinter.py" file from the directory!
from Tkinter import *
import tkinter as tk # python3
TITLE_FONT = ("Helvetica", 18, "bold")
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container is where I stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = tk.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 (MainPage,StorageOrMotor,Storage,Motor):
page_name = F.__name__
frame = F(container, self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("MainPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class MainPage(tk.Frame):
global user_key
global psw_key
user_key=""
psw_key=""
#Here is the defined for clear_message `def`
def clear_message():
user_key.delete(0, 'END')
psw_key.delete(0, 'END')
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Username = tk.Label(self, text="Username:",font=("Helvetica", "20","bold"))
Username.grid(row=2, column=3,columnspan=2)
Password = tk.Label(self, text="Password:",font=("Helvetica", "20","bold"))
Password.grid(row=3, column=3,columnspan=2)
#............
Username_key = tk.Entry(self, textvariable = user_key, width=19, font=("Helvetica", "15"))
Username_key.grid(row=2, column=5,columnspan=5)
Password_key = tk.Entry(self, textvariable = psw_key, width=19, font=("Helvetica", "15"))
Password_key.grid(row=3, column=5,columnspan=5)
log_in = tk.Button(self, width=7, text="Log In", command=lambda: controller.show_frame("StorageOrMotor"))
log_in.grid(row=5,column=8,columnspan=2)
#............`I try to create a clear button`
Clear = tk.Button(self, width=7, text=" Clear " ,command=lambda:clear_message())
Clear.grid(row=5,column=5,columnspan=2)
clear_message() belongs to MainPage class so when calling it inside that class, you need to use self. prefix. Also, you need to use self as a parameter when defining the method since it is a member of a class.
def clear_message(self): #self here
user_key.delete(0, 'END')
psw_key.delete(0, 'END')
Additionally, since clear_message doesn't take any arguments, you don't need a lambda expression there.
#self here and removed lambda
Clear = tk.Button(self, width=7, text=" Clear " ,command=self.clear_message)
This problem appears to be hard to duplicate -- as I am able to correctly do it in a shorter program. What I'm hoping for is maybe some guidance on what could be going wrong. I have posted the version where it works correctly:
import tkinter as tk
from tkinter import *
from tkinter import ttk
class DIS(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "program")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.usernameVar = StringVar()
self.frames = {}
for F in (StartPage, contactQues, nowTry, next):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button2 = ttk.Button(self, text = "Here's a Button", command= lambda: controller.show_frame(nowTry))
button2.pack()
class nowTry(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.entry1 = Entry(self)
self.entry1.pack()
self.button1 = ttk.Button(self, text = "Yes", command = self.go)
self.button1.pack()
self.entry1.bind("<Return>", self.go)
def go(self, event=None):
print (self.entry1.get())
self.controller.show_frame(contactQues)
class contactQues(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.entry1 = Entry(self)
self.entry1.pack(pady=10, padx=10)
self.button1 = ttk.Button(self, text = "Submit", command= self.UsernameSubmit)
self.button1.pack()
self.entry1.bind("<Return>", self.UsernameSubmit)
def UsernameSubmit(self, event=None):
UsernameEntryGet = self.entry1.get()
self.controller.usernameVar.set(UsernameEntryGet)
self.controller.show_frame(next)
class next(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, textvariable = self.controller.usernameVar)
label.pack() ###Label is posted with input correctly
The issue I'm having with my main program is that the self.controller.usernameVar label does not post like it does in this example (nothing shows up at all) when the Return key is pressed to submit the input. However, when the submit button is clicked with the mouse, the label appears properly.
So, given this information, I feel as if my bind("<Enter>"... command is being managed wrong. I've tried self.bind..., self.controller.bind..., self.entryX.bind... without success.
Any ideas with this framework what could be wrong?
I believe I figured it out. The issue was that in my full program, I had multiple bind commands. While I was trying to solve this issue, I had some entry prompts bound to the controller and others to the entry itself (e.g,. self.controller.bind in a few classes and self.entry.bind in others).
I changed them all to self.entry.bind and it apparently fixed it -- which is why this code snippet worked as expected.