Passing variables between different classes and definition in tkinter - python

I have a problem with my code. I am unable to pass a variable to another class once a submit button is pressed in my tkinter frame.
I have followed the advice from a post already (How to access variables from different classes in tkinter?), which has helped but I still have issues.
From where to where I need these variables is commented on the code below:
import tkinter as tk
from tkinter import StringVar
LARGE_FONT = ("Verdana", 12)
class Club(tk.Tk):
def get_page(self, page_class):
return self.frames[page_class]
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.shared_data = {
"username": tk.StringVar(),
"password": tk.StringVar(),
}
self.frames = {}
for F in (Terminal, newUser, newUserSubmitButton, delUser):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(Terminal)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class Terminal(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Welcome to the club terminal. Click the options below", font=LARGE_FONT)
label.grid(columnspan=3)
button = tk.Button(self, text="Visit new User",
command=lambda: controller.show_frame(newUser))
button.grid(row=1, column=0)
button2 = tk.Button(self, text="Visit del User",
command=lambda: controller.show_frame(delUser))
button2.grid(row=1, column=1)
class newUser(tk.Frame):
def __init__(self, parent, controller):
def submitButton():
username = self.controller.shared_data["username"].get()
print(username)
controller.show_frame(newUserSubmitButton)
##username variable from here to...
tk.Frame.__init__(self, parent)
welcomelabel = tk.Label(self, text="Add New User/s", font=LARGE_FONT)
welcomelabel.grid(columnspan=2, sticky="ew")
userNameLabel = tk.Label(self, text="Username")
userNameLabel.grid(row=1, column=0, sticky="e")
userNameEntry = tk.Entry(self, textvariable=self.controller.shared_data["username"])
userNameEntry.grid(row=1, column=1)
userMemTypeLabel = tk.Label(self, text="Membership Type")
userMemTypeLabel.grid(row=2, column=0, sticky="e")
variable = StringVar(self)
variable.set("Full")
userMemTypeMenu = tk.OptionMenu(self, variable, "Full", "Half")
userMemTypeMenu.grid(row=2, column=1)
userMemYearsLabel = tk.Label(self, text="Years that member is in the club")
userMemYearsLabel.grid(row=3, column=0, sticky="e")
userMemYearsEntry = tk.Entry(self)
userMemYearsEntry.grid(row=3, column=1)
self.controller = controller
newusersubmitbutton = tk.Button(self, text="submit", command=submitButton)
newusersubmitbutton.grid(columnspan=2)
class newUserSubmitButton(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
##username variable goes here
page1 = self.controller.get_page(newUser.submitButton)
page1.username.set("Hello, world")
print(page1)
class delUser(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="del User!!!", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(Terminal))
button1.pack()
button2 = tk.Button(self, text="new User",
command=lambda: controller.show_frame(newUser))
button2.pack()
app = Club()
app.title("Club Terminal")
app.iconbitmap("table.ico")
app.mainloop()
Whenever I run this code, I get an AttributeError: 'newUser' object has no attribute 'controller'.
Any help is greatly appreciated, I'll be more than happy to try any ideas out.
With regards.

There are more problems in this code, but to solve that one, add the line:
self.controller=controller
To the newUser classes __init__ function.

Related

Cannot call show_frame function in tkinter outise of its class

With the code below (that I took from sentdex) I am trying to raise PageOne window when the correct password("123") is inserted in the first page. However, I get the error: TypeError: show_frame() missing 1 required positional argument: 'cont'. Isn't PageOne the argument ? Why is not working ? Could you also please explain what "controller" variable does ?
Thank you very much in advance.
import tkinter as tk
import tkinter as tk
from PIL import Image,ImageTk
LARGE_FONT= ("Verdana", 12)
class Root(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 (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)
self.entry=tk.Entry(self, width = 35)
self.entry.insert(0, 'Enter password')
self.entry.config(fg = "grey")
# entry.bind('<FocusIn>', self.EntryFieldClicked)
# entry.bind("<Return>", (lambda event: self.SubmitPass()))
self.entry.place(relx=.5, rely=.3,anchor = tk.CENTER)
button=tk.Button( self,text="Show Password", width = 20,command = self.ShowPass).place(relx=.5, rely=.4,anchor = tk.CENTER)
button=tk.Button(self,text="Submit",width = 20, command=self.SubmitPass).place(relx=.5, rely=.5,anchor = tk.CENTER)
self.entry.config(fg = "grey")
self.entry.bind('<FocusIn>', self.EntryFieldClicked)
self.entry.bind("<Return>", (lambda event: self.SubmitPass ))
label=tk.Label(self,text="Log in to continue")
label.pack()
button = tk.Button(self, text="Visit Page 1",
command=lambda: controller.show_frame(PageOne))
button.pack()
def EntryFieldClicked(self,event):
if self.entry.get() == 'Enter password':
self.entry.delete(0, tk.END)
self.entry.insert(0, '')
self.entry.config(fg = 'black', show = "*")
def ShowPass(self):
self.entry.config(fg = 'black', show = "")
def SubmitPass(self):
global Password
Password = self.entry.get()
if Password == "123":
Root.show_frame(PageOne)
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.pack(pady=10,padx=10)
self.controller = controller
button1 = tk.Button(self, text="Back to Home",
command=lambda: self.controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Page Two",
command=lambda: controller.show_frame(PageTwo))
button2.pack()
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.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button2 = tk.Button(self, text="Page One",
command=lambda: controller.show_frame(PageOne))
button2.pack()
app = Root()
app.mainloop()
Blockquote
The problem is this line:
Root.show_frame(PageOne)
You are calling the method on the class rather than the instance, so the first argument is passes to the self parameter.
Your class needs to keep a reference to the controller, so that you can call the method via the controller.
class StartPage(tk.Frame):
def __init__(self, parent, controller):
self.controller = controller
...
def SubmitPass(self):
global Password
Password = self.entry.get()
if Password == "123":
self.controller.show_frame(PageOne)

Returning variables in tkinter when using classes? [duplicate]

This question already has answers here:
How to get variable data from a class?
(2 answers)
Closed 1 year ago.
I'm looking for advice on how to solve my problem. I need a way to save the entries list in my saveInput() method so I can access it later outside the class with a different function. The only solution I have come up with is a global variable but I'm told they are the devil and I should try to avoid them when they are not constant. If anybody could give me a solution I would greatly appreciate it. My code is below, including the CSV file.
from tkinter import font as tkfont # python 3
import tkinter as tk
import csv
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")
# 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 = {}
for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):
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="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Enter airport details",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Enter flight details",
command=lambda: controller.show_frame("PageTwo"))
button3 = tk.Button(self, text="Enter price plan and calculate profit",
command=lambda: controller.show_frame("PageThree"))
button4 = tk.Button(self, text="Clear data",
command=lambda: controller.show_frame("PageFour"))
button1.pack()
button2.pack()
button3.pack()
button4.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
ukAirportOptionList = [
"LPL",
"BOH"
]
foreignAirportList = []
with open('Airports.csv', 'r') as fd:
reader = csv.reader(fd)
for row in reader:
foreignAirportList.append(row)
tk.Label(self, text="Airport Details", font=controller.title_font).grid()
ukAirportTracker = tk.StringVar()
ukAirportTracker.set("Select the UK Airport")
tk.OptionMenu(self, ukAirportTracker, *ukAirportOptionList).grid()
foreignAirportTracker = tk.StringVar()
foreignAirportTracker.set("Select the Oversea Airport")
tk.OptionMenu(self, foreignAirportTracker, *[airport[0] for airport in foreignAirportList]).grid()
saveButton = tk.Button(self, text="Save",
command=lambda: [controller.show_frame("StartPage"),
self.saveInput(ukAirportTracker, foreignAirportTracker)])
saveButton.grid(row=3, column=1)
def saveInput(self, *args):
enteries = []
for arg in args:
enteries.append(arg.get())
print(enteries)
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
aircraftTypesList = [['medium narrow body', 8, 2650, 180, 8],
['large narrow body', 7, 5600, 220, 10],
['medium wide body', 5, 4050, 406, 14]]
label = tk.Label(self, text="Flight Details", font=controller.title_font)
label.grid()
aircraftTypeTracker = tk.StringVar()
aircraftTypeTracker.set("Aircraft Type")
tk.OptionMenu(self, aircraftTypeTracker, *[aircraft[0] for aircraft in aircraftTypesList]).grid()
saveButton = tk.Button(self, text="Save",
command=lambda: [controller.show_frame("StartPage"), self.saveInput(aircraftTypeTracker)])
saveButton.grid()
def saveInput(self, *args):
enteries = []
for arg in args:
enteries.append(arg.get())
print(enteries)
class PageThree(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
tk.Label(self, text="This is page 3", font=controller.title_font).grid(row=0, column=0)
tk.Label(self, text="Price of Standard Seat").grid(row=1)
tk.Label(self, text="Price of First Class Seat").grid(row=2)
e1 = tk.Entry(self)
e2 = tk.Entry(self)
e1.grid(row=1, column=1)
e2.grid(row=2, column=1)
saveButton = tk.Button(self, text="Save",
command=lambda: [controller.show_frame("StartPage"), self.saveInput(e1, e2)])
saveButton.grid(row=3, column=1)
def saveInput(self, *args):
enteries = []
for arg in args:
enteries.append(arg.get())
print(enteries)
class PageFour(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 4", font=controller.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()
The csv file:
JFK,John F Kennedy International,5326,5486
ORY,Paris-Orly,629,379
MAD,Adolfo Suarez Madrid-Barajas,1428,1151
AMS,Amsterdam Schiphol,526,489
CAI,Cairo International,3779,3584
A way to mostly✶ avoid global variables in this case is to make the local variable enteries an instance attribute of some class. In this case I chose the SampleApp "controller" this tkinter app architecture defines. (Note I also changed its name to entries in the modified code below.)
✶ I say that because it's very difficult to not have any.
Disclaimer: I don't quite understand what you want or are planning to put into the enteries list in each Page class of you code, so the results below merely do the same as in your code. I'm also not sure what you mean by "returning variables" because classes are objects and don't return anything per se. They can be containers of data and have methods that return values — but you don't have any examples of that in your question's code. To rectify that I added a Quit button to demonstrate how the data could be retrieved.
Anyway, I made the modifications needed to do that in code below. In addition, I noticed there was a lot of replicated / very similar code in each Page class, so I defined a private base class named _BasePage and derived all the others from it. This allowed me to put the common code in there and is an example of apply the DRY principle which is another benefit of using classes.
from tkinter import font as tkfont # python 3
import tkinter as tk
import csv
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")
self.entries = [] # Accumulated entries.
# 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 = {}
for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):
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 _BasePage(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
self.controller = controller
def saveInput(self, *string_vars):
strings = [var.get() for var in string_vars]
print(f'adding entries: {strings}')
self.controller.entries.extend(strings)
class StartPage(_BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
tk.Button(self, text="Enter airport details",
command=lambda: controller.show_frame("PageOne")).pack()
tk.Button(self, text="Enter flight details",
command=lambda: controller.show_frame("PageTwo")).pack()
tk.Button(self, text="Enter price plan and calculate profit",
command=lambda: controller.show_frame("PageThree")).pack()
tk.Button(self, text="Clear data",
command=lambda: controller.show_frame("PageFour")).pack()
tk.Button(self, text="Quit",
command=self.quit).pack() # Terminate mainloop().
class PageOne(_BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
ukAirportOptionList = [
"LPL",
"BOH"
]
foreignAirportList = []
with open('Airports.csv', 'r') as fd:
reader = csv.reader(fd)
for row in reader:
foreignAirportList.append(row)
tk.Label(self, text="Airport Details", font=controller.title_font).grid()
ukAirportTracker = tk.StringVar()
ukAirportTracker.set("Select the UK Airport")
tk.OptionMenu(self, ukAirportTracker, *ukAirportOptionList).grid()
foreignAirportTracker = tk.StringVar()
foreignAirportTracker.set("Select the Oversea Airport")
tk.OptionMenu(self, foreignAirportTracker,
*[airport[0] for airport in foreignAirportList]).grid()
saveButton = tk.Button(self, text="Save", command=lambda:
[controller.show_frame("StartPage"),
self.saveInput(ukAirportTracker, foreignAirportTracker)])
saveButton.grid(row=3, column=1)
class PageTwo(_BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
aircraftTypesList = [['medium narrow body', 8, 2650, 180, 8],
['large narrow body', 7, 5600, 220, 10],
['medium wide body', 5, 4050, 406, 14]]
label = tk.Label(self, text="Flight Details", font=controller.title_font)
label.grid()
aircraftTypeTracker = tk.StringVar()
aircraftTypeTracker.set("Aircraft Type")
tk.OptionMenu(self, aircraftTypeTracker,
*[aircraft[0] for aircraft in aircraftTypesList]).grid()
saveButton = tk.Button(self, text="Save", command=lambda:
[controller.show_frame("StartPage"),
self.saveInput(aircraftTypeTracker)])
saveButton.grid()
class PageThree(_BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
tk.Label(self, text="This is page 3",
font=controller.title_font).grid(row=0, column=0)
tk.Label(self, text="Price of Standard Seat").grid(row=1)
tk.Label(self, text="Price of First Class Seat").grid(row=2)
e1 = tk.Entry(self)
e2 = tk.Entry(self)
e1.grid(row=1, column=1)
e2.grid(row=2, column=1)
saveButton = tk.Button(self, text="Save",
command=lambda: [controller.show_frame("StartPage"),
self.saveInput(e1, e2)])
saveButton.grid(row=3, column=1)
class PageFour(_BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
label = tk.Label(self, text="This is page 4", font=controller.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()
print('Final entries:')
for entry in app.entries:
print(f' {entry}')

Updating or "Refreshing" frames in Tkinter

This basically creates all the frames and brings the one we call to the front right?
So as some variables change i want the frames to change accordingly, i tried a few refreshing functions i found while searching in google but none of them worked in this code.
oooooooooooooooooooooooooooooo
Code:
import tkinter as tk
from tkinter import *
from tkinter import ttk
from functools import partial
class MovieTicketapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.geometry(self, "500x400")
container = tk.Frame(self)
container.pack(side='top', fill='both', expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
global user
self.frames = {}
for F in (StartPage, SignUp, Login, EditMovie):
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)
global user
button_signup = ttk.Button(self, text='Sign Up',
command=lambda: controller.show_frame(SignUp)).pack(pady=10, padx=15)
button_EditMovie = ttk.Button(self, text='Edit Movie Details',
command=lambda: controller.show_frame(EditMovie))
if user == "admin":
button_EditMovie.pack(pady=10, padx=15)
class SignUp(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button_login = ttk.Button(self, text='Login',
command=lambda: controller.show_frame(Login)).pack(pady=10, padx=15)
button_home = tk.Button(self, text='Home',
command=lambda: StartPage.__init__()).pack(pady=10, padx=15)
class Login(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def validateLogin(email, password):
e = email.get()
p = password.get()
global user
user = e
StartPage.update(self)
controller.show_frame(StartPage)
self.pack_forget()
emailLabel = tk.Label(self, text='Email').pack()
email = tk.StringVar()
emailEntry = tk.Entry(self, textvariable = email).pack()
passwordLabel = tk.Label(self,text="Password").pack()
password = tk.StringVar()
passwordEntry = tk.Entry(self, textvariable=password, show='*').pack()
validateLogin = partial(validateLogin, email, password)
loginButton = tk.Button(self, text="Login", command= validateLogin).pack(pady=15, padx=15)
button_home = tk.Button(self, text='Home',
command=lambda: controller.show_frame(StartPage)).pack(pady=10, padx=15)
class EditMovie(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button_home = tk.Button(self, text='Home',
command=lambda: controller.show_frame(StartPage))
button_home.pack(pady=10, padx=10)
app = MovieTicketapp()
app.mainloop()
......

Issues with .grid in Tkinter

I am VERY new to coding/Python, but basically I am trying to move a button and label around using .grid, however, the button and label in the StartPage class just won't move to where I ask (or even at all).
Everything in the BMR class works fine (although the positions you see aren't the final positions, I was just checking).
What is the difference? Why do they not appear at the same position if I give the same details in both classes?
import tkinter as tk
class initials(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 (StartPage, BMR):
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): #GRID WON'T WORK HOW I WANT IT TO
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Start Page")
label.grid(column=3, row=3, sticky='we')
button = tk.Button(self, text="Calculate BMR",
command=lambda: controller.show_frame(BMR))
button.grid(row=4, column=3, sticky='we')
class BMR(tk.Frame): #GRID WORKS PERFECTLY
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="BMR Calculator")
label.grid(column=1,row=1)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.grid(column=2, row=2)
submit = tk.Button(self, text="Calculate")
submit.grid(column=3, row=3)
var1 = tk.IntVar()
tk.Checkbutton(self, text='Male', bg='white', variable=var1).grid(column=4, row=4)
var2= tk.IntVar()
tk.Checkbutton(self, text='Female', bg='white', variable=var2).grid(column=5, row=5)
height_inp = tk.Entry(self, width=20, bg="white").grid(column=6, row=6)
app = initials()
app.mainloop()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Start Page", width = 80)
# Added width property in the line above
# and changed sticky property to N
label.grid(row = 3, column=3, sticky = 'N')
label.width = 20
button = tk.Button(self, text="Calculate BMR",
command=lambda: controller.show_frame(BMR))
button.grid(row=4, column=3)
# Removed sticky property for the button
I understand this is how you wish to position the label and the button.
Pleaase see the comments. You can edit the value for the width property and make it suitable for your frame.

Object Orientated Tkinter Functions - How would I put this in?

I am coding a program which will need functions to change labels and enter text into text boxes however I do not know how to do this with a new style of programming which I am using (Object Orientated). I have done the program before however I generated the frames using this code:
f = [Frame(root) for i in range(0,5)]
for i in f:
i.place(relx=0,rely=0,relwidth=1,relheight=1)
and then I put it all in one class which I ran however that was bad form so I am redoing it. My code so far is as follows:
import tkinter as tk
import datetime,time,os,sys
import sqlite3 as lite
from datetime import date
Title_Font= ("Times", 18, "underline italic")
unix = time.time()
time_curr = str(datetime.datetime.fromtimestamp(unix).strftime('%H:%M'))
date1 = str(datetime.datetime.fromtimestamp(unix).strftime('%d-%m-%Y'))
class Creating_Stuff(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 (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)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(3, weight=1)
self.option_add( "*font", "Times 12" )
self.tk_setPalette(background='#bbfff0', foreground='black',
activeBackground='#d9d9d9', activeForeground='#ff9933')
label = tk.Label(self, text="Laptop Booking System", font=Title_Font)
label.grid(row=0, column=1, pady = 30)
time = tk.Label(self, text="Time: " + time_curr + "\nDate: " + date1, font="Times 10")
time.grid(row=0, column=2,columnspan=2)
Booking_1 = tk.Button(self, text="Booking",
command=lambda: controller.show_frame(PageOne),bg='#f2f2f2',width=20)
Booking_1.grid(row=2, column=1, pady=10)
Tbl_q1 = tk.Button(self, text="Table Querying",
command=lambda: controller.show_frame(PageTwo),bg='#f2f2f2',width=20)
Tbl_q1.grid(row=3, column=1, pady=10)
Exit = tk.Button(self, text ="Exit",command=lambda:destroy(),bg='#f2f2f2')
Exit.grid(row=5, column=1)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(3, weight=1)
label = tk.Label(self, text="Page One!!!", font=Title_Font)
label.grid(row=1, column=1)
bk2_menu = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
bk2_menu.grid(row=3, column=1)
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(3, weight=1)
label = tk.Label(self, text="Page Two!!!", font=Title_Font)
label.grid(row=1, column=1)
bk2_Menu2 = tk.Button(self, text="Back to menu",
command=lambda: controller.show_frame(StartPage))
bk2_Menu2.grid(row=3, column=1)
app = Creating_Stuff()
def destroy():
app.destroy()
app.title("Laptop Booking System")
app.geometry("700x400")
app.mainloop()
If you try it out it works however it just has 3 different frames. How can I get a button in a frame to make a label say "Hello" in the frame after it is pressed?
I've modified one of your page classes to illustrate how it could be done. It involved adding a Label to hold the message, a Button to control it, and a function, called simply handler(), to call when the latter is pressed. It saves the widgets by making them attributes of the containing Frame subclass instance, self, so they can be easily referenced in the handler() function (without resorting to global variables).
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(3, weight=1)
label = tk.Label(self, text="Page One!!!", font=Title_Font)
label.grid(row=1, column=1)
self.msg_label = tk.Label(self, text="")
self.msg_label.grid(row=2, column=1)
self.msg_button = tk.Button(self, text='Show Message',
command=self.handler)
self.msg_button.grid(row=3, column=1)
self.msg_toggle = False
bk2_menu = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
bk2_menu.grid(row=5, column=1)
def handler(self):
self.msg_toggle = not self.msg_toggle
if self.msg_toggle:
self.msg_label.config(text='Hello')
self.msg_button.config(text='Clear Message')
else:
self.msg_label.config(text='')
self.msg_button.config(text='Show Message')
Screenshots
Before button is pressed:
After button is pressed:

Categories

Resources