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()
Related
Sorry about the layout of this question, my first time working with stackoverflow posts.
I want to make a GUI for Tic Tac Toe (Game menu). And have the abillity to put buttons where ever i want in the GUI so i used Grid.
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
class SeaofBTCapp(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 (MainWindow, Game, Difficulty):
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 MainWindow(tk.Tk):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Welcom to TIC TAC TOE", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Start",
command=lambda: controller.show_frame(Game))
button1.pack()
button2 = tk.Button(self, text="Diffeculty",
command=lambda: controller.show_frame(Difficulty))
button2.pack()
button3 = tk.Button(self, text="Quit", command=self.Quit)
button3.pack()
label1 = tk.Label(self, text="Made by VindictaOG")
label1.pack()
def Quit(self):
exit()
class Game(tk.Tk):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = tk.Button(self, text="New Game")
button1.pack()
button2= tk.Button(self, text="Back to homescreen",
command=lambda: controller.show_frame(MainWindow))
button2.pack()
class Difficulty(tk.Tk):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = tk.Button(self, text="1V1", command=lambda: controller.show_frame(MainWindow))
button1.pack()
button2 = tk.Button(self, text="Back to homescreen",
command=lambda: controller.show_frame(Game))
button2.pack()
gui = SeaofBTCapp()
gui.mainloop()
But when i use grid i get this error:
Traceback (most recent call last):
File "/home/ivar/PycharmProjects/J1B2Afvink6/BKE.py", line 82, in <module>
gui = SeaofBTCapp()
File "/home/ivar/PycharmProjects/J1B2Afvink6/BKE.py", line 27, in __init__
frame.grid(row=0, column=0, sticky="nsew")
TypeError: wm_grid() got an unexpected keyword argument 'row'
I tried it with pack but that would not work, does someone know how to fix this?
Should inherit from tk.Frame instead of tk.Tk for MainWindow, Game and Difficulty. Also StartPage is not defined. #acw1668
Using (tk.Frame, tk.Tk) instead of just (tk.Tk) solved the problem.
I am a beginner in programming in python and I have a question. With the code shown below, is it possible to give each class (which represent a different page) a different title and not a title to all the pages at once? I have looked everywhere and have been unable to find an answer. Thank you!
import tkinter as tk
# from tkinter import *
# Activate the line above when a message box is needed
class Start(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)
self.title("Application")
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne):
# To add a new page, define the class below and then add the frame to the For Loop above
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, controller):
frame = self.frames[controller]
frame.tkraise()
def get_page(self, page_class):
return self.frames[page_class]
# This is the end of the baseline and the code for each page is below:
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Name = StringVar()
Password = StringVar()
def show_credentials(event):
instructions = tk.Label(self, text="Credentials: ")
instructions.grid(row=5, column=3, sticky="E")
names = Name.get()
passwords = Password.get()
names = tk.Label(self, text=names, bg="red", fg="white")
passwords = tk.Label(self, text=passwords, bg="Red", fg="white")
names.grid(row=6, column=3, sticky="E")
passwords.grid(row=7, column=3, sticky="E")
credentials = tk.Button(self, text="Creds")
credentials.bind("<Button-1>", show_credentials)
credentials.grid(row=4, column=3, sticky="E")
def login(event):
controller.show_frame(PageOne)
log = tk.Button(self, text="Log In")
log.bind("<Button-1>", login)
log.grid(row=4, column=4, sticky="E")
# A class can be created to compare data entered to a list to identify the user and log him/her in
welcome = tk.Label(self, text="Welcome!")
welcome.grid(row=0, column=2, sticky="E")
username = tk.Label(self, text="Username: ")
username.grid(row=2, column=2, sticky='E')
password_label = tk.Label(self, text="Password: ")
password_label.grid(row=3, column=2, sticky="E")
username_entry = tk.Entry(self, textvariable=Name)
username_entry.grid(row=2, column=3, sticky="E")
password_entry = tk.Entry(self, textvariable=Password, show="*")
password_entry.grid(row=3, column=3, sticky="E")
cancel = tk.Button(self, text="Exit", command=quit)
cancel.grid(row=4, column=2, sticky="E")
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This page is currently under Development")
label.grid(row=0, column=0, sticky="E")
switchpage1 = tk.Button(self, text="Back", command=lambda: controller.show_frame(StartPage))
switchpage1.grid(row=1, column=0, sticky="E")
root = Start()
root.mainloop()
Here is a way to title a different window:
import tkinter as tk
root = tk.Tk()
window1 = tk.Toplevel(root)
window1.wm_title("window 1")
root.mainloop()
I would like to employ multiple frames in a GUI, where the page switches depending on the button clicked. I know that there's several threads already about this, and I've been looking at this one.
However, for my pages, I need different images on canvasses within each of my frames, so that when I raise a different frame, it comes with a new canvas and a new image on that canvas. I've tried a lot but I don't know how to get it to work so that the canvasses appear with their images.
Here's what I have so far, mostly copying from above link:
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 we'll 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 = {}
self.frames["StartPage"] = StartPage(parent=container, controller=self)
self.frames["PageOne"] = PageOne(parent=container, controller=self)
self.frames["PageTwo"] = PageTwo(parent=container, controller=self)
self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
self.frames["PageOne"].grid(row=0, column=0, sticky="nsew")
self.frames["PageTwo"].grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given 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._canvas = tk.Canvas(parent, bg='white', width=900, height=3517, scrollregion=(0, 2800, 100, 800))
self._photo = tk.PhotoImage(file='images/homegraphic.gif')
self._canvas.create_image(0, 0, image=self._photo, anchor='nw')
label = tk.Label(self, text="This is the start page", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
How do I get the canvas image to appear? I've spent a long time trying to figure this out and would appreciate any help!
The problem is here:
self._canvas = tk.Canvas(parent, ...)
Everything within a page needs to be a child of the page or one of its descendants.
It needs to be this:
self._canvas = tk.Canvas(self, ...)
i am trying out my first program and would appreciate if someone would tell me what is going on wrong. i wrote this program to pop up a screen with 4 choices and when i click on one of those choices it should switch screen to the next screen, please advice what did i wrote wrong because all what i am getting is the first screen then nothing when i click on the buttons thank you.
here is the program
import tkinter as tk
LARGE_FONT = ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
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, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
btn1 = tk.Button(text="", fg="white", width=400, height=240, command=lambda : controller.show_frame(PageOne))
btn1["bg"] = "white"
mi = tk.PhotoImage(file="C:\\Python\\trials\\pic1.gif")
btn1.config(image=mi)
btn1.image = mi
btn2 = tk.Button(text="", fg="white", width=400, height=240, command=lambda: controller.show_frame(PageTwo))
btn2["bg"] = "white"
mi1 = tk.PhotoImage(file="C:\\Python\\trials\\safety.gif")
btn2.config(image=mi1)
btn2.image = mi1
btn3 = tk.Button(text="", fg="white", width=400, height=240)
btn3["bg"] = "white"
mi2 = tk.PhotoImage(file="C:\\Python\\trials\\count.gif")
btn3.config(image=mi2)
btn3.image = mi2
btn4 = tk.Button(text="", fg="white", width=400, height=240)
btn4["bg"] = "white"
mi3 = tk.PhotoImage(file="C:\\Python\\trials\\about.gif")
btn4.config(image=mi3)
btn4.image = mi3
btn1.grid(row=0, column=0, columnspan=1, sticky='EW')
btn2.grid(row=0, column=1, columnspan=1, sticky='EW')
btn3.grid(row=1, column=0, columnspan=1, sticky='EW')
btn4.grid(row=1, column=1, columnspan=1, sticky='Ew')
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page One!!!", font=LARGE_FONT)
label.grid(pady=10, padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.grid()
button2 = tk.Button(self, text="Page Two",
command=lambda: controller.show_frame(PageTwo))
button2.grid()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT)
label.grid(pady=10, padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.grid()
button2 = tk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.grid()
app = SeaofBTCapp()
app.mainloop()
You have 2 problems:
First, all of your Buttons need to have the first argument 'self'. You did this in some places but you forgot it in the StartPage class.
Second, you need to layout your container. Add a pack() after you initialize it:
container = tk.Frame(self)
container.pack()
I want to pass entry values from one class to another using the get() method and i dont know how. Thanks in advance
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container is where we'll 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.x=tk.StringVar()
self.y=tk.StringVar()
self.key=tk.IntVar()
self.key.set(0)
self.frames = {}
for F in (StartPage, PageOne, PageTwo, LoggedIn, Balance):
page_name = F.__name__
frame = F(parent=container, controller=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("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given 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="Banking Application", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="User Login",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Create Account",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
This is from where i want to pass the userid entry value to Balance class
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Login Page", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
#user id entry block
tk.Label(self,text="UserID").pack(side="top", fill="x", pady=4)
self.userid=tk.Entry(self,textvariable=self.controller.x)
self.userid.pack(side="top", fill="x", pady=6)
#password entry block
tk.Label(self,text="Password").pack(side="top", fill="x", pady=4)
self.password=tk.Entry(self,textvariable=self.controller.y)
self.password.pack(side="top", fill="x", pady=6)
self.submit=tk.Button(self, text="SUBMIT",
command=self.login)
self.submit.pack();
button = tk.Button(self, text="Back to Main Menu",
command=lambda: controller.show_frame("StartPage"))
button.pack()
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
def getname(self):
name=self.controller.x.get()
print (name)
return name
def login(self):
getname(self);
for x in range(0,listsize):
if(self.controller.x.get()==files[x]):
print("welcome %s"%(self.controller.x.get()))
if(self.controller.y.get()==keys[x]):
bal=open(self.controller.x.get()+'.txt','r')
currbal=int(bal.read())
print("login success")
self.controller.key.set(1)
# print(self.controller.key=1)
self.controller.show_frame("LoggedIn");
break
else:
print("Invalid credentials")
How to pass userid from pageone to this class
class Balance(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Balance Enquiry", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
username = PageOne.getname(self);
print(username)
if(self.controller.key==1):
print(username)
bal=open(username+'.txt','r')
currbal=int(bal.read())
label1 = tk.Label(self, text=currbal)
label1.pack(side="top", fill="x", pady=10)
###########
button = tk.Button(self, text="Go to the savings page",
command=lambda: controller.show_frame("LoggedIn"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()