Related
I've been trying to call the class that is in my mainloop, but whenever I properly call it makes it that the program doesn't even launch anymore. I've been attempting to call it in order to get a method, which would return the current frame. I am aware that my code uses controller and parent to communicate between classes, but I haven't managed to fully grasp an understanding of these. If I call the mainlooped class, with "test = Database_project()", then the program won't run anymore. Can someone explain this to me? I'm trying to get the scrollbar feature to work on specific frames, and I haven't managed to figure out just yet. I'm trying to call the mainlooped class in the "CreatePage" class. Thank you in advance!
from tkinter import *
import tkinter as tk
class Database_Project(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
stack_frame_container = tk.Frame(self)
stack_frame_container.grid_columnconfigure(0, weight=1)
stack_frame_container.grid_rowconfigure(0, weight=1)
stack_frame_container.pack(side="top", fill="both", expand=True)
self.frameslist = {}
for frame in (MainPage, CreatePage):
frame_occurrence = frame.__name__
active_frame = frame(parent=stack_frame_container, controller=self)
self.frameslist[frame_occurrence] = active_frame
active_frame.grid(row=0, column=0, sticky="snew")
#self.frameslist["CreatePage"].dbproject = self.frameslist["Datanase_Project"]
self.current_frame("MainPage")
print(self.frameslist)
def current_frame(self, frame_occurrence):
active_frame = self.frameslist[frame_occurrence]
active_frame.tkraise()
def get_current_frame(self, frame_occurrence):
active_frame = self.frameslist[frame_occurrence]
return active_frame
class MainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label_create = tk.Label(self, text="Create and insert data").grid(row=0, column=0, padx=50, pady=(50,0))
create_button = tk.Button(self, text="CREATE", command=lambda: controller.current_frame("CreatePage")).grid(row=1, column=0)
label_read = tk.Label(self, text="Query over data").grid(row=0, column=1, padx=50, pady=(50,0))
read_button = tk.Button(self, text="READ").grid(row=1, column=1)
label_update = tk.Label(self, text="Modify existing data").grid(row=2, column=0, padx=50, pady=(50,0))
update_button = tk.Button(self, text="UPDATE").grid(row=3, column=0, pady=(0,50))
label_delete = tk.Label(self, text="Remove data").grid(row=2, column=1, padx=50, pady=(50,0))
delete_button = tk.Button(self, text="DELETE").grid(row=3, column=1, pady=(0,50))
class CreatePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.inputlist = []
self.newinputlist = []
Test = Database_Project()
#active_frame = Test.get_current_frame("CreatePage")
#scrollbar = tk.Scrollbar(active_frame, orient="vertical")
#scrollbar.grid(row=0, column=2, stick="ns", columnspan=10)
#text["yscrollcommand"] =
labels = [tk.Label(self, text="Enter unique field"), tk.Label(self, text="Enter corresponding the value/s")]
self.inputlist.append(labels[:])
for toplabels in range(1):
self.inputlist[toplabels][0].grid(row=toplabels, column=0, padx=10, pady=5)
self.inputlist[toplabels][1].grid(row=toplabels, column=1, padx=10, pady=5)
first_entries = [tk.Entry(self, borderwidth=5), tk.Text(self, borderwidth=5, height= 5, width=20)]
self.newinputlist.append(first_entries[:])
self.inputlist.append(first_entries[:])
for x in range(0, len(self.newinputlist) + 1):
self.newinputlist[0][x].grid(row=1, column=x, padx=10, pady=5)
button_input_1 = [tk.Button(self, text="ADD FIELD/VALUE", command=self.add_insert), tk.Button(self, text="BACK", command=lambda: controller.current_frame("MainPage"))]
self.inputlist.append(button_input_1[:])
button_input_2 = [tk.Button(self, text="IMPORT FILE"), tk.Button(self, text="SUBMIT DATA", command=self.submit_data)]
self.inputlist.append(button_input_2[:])
for button in range(len(self.inputlist) - 2, len(self.inputlist)):
self.inputlist[button][0].grid(row=button, column=0, padx=10, pady=5)
self.inputlist[button][1].grid(row=button, column=1, padx=10, pady=5)
def add_insert(self):
add_input = [tk.Entry(self, borderwidth=5), tk.Text(self, borderwidth=5, height= 5, width=20)]
self.inputlist.insert(-2, add_input)
self.newinputlist.append(add_input)
for widget in self.children.values():
widget.grid_forget()
for index, widgets in enumerate(self.inputlist):
print(widgets)
widget_one = widgets[0]
widget_two = widgets[1]
print(str(index), widget_one, widget_two)
widget_one.grid(row=index, column=0, padx=10, pady=5)
widget_two.grid(row=index, column=1, padx=10)
def submit_data(self):
for index, entries in enumerate(self.newinputlist):
my_label = Label(self, text=str(entries[0].get()) + str(entries[1].get("1.0", END)))
my_label.grid(row=len(self.inputlist) + index, column=0)
if __name__ == "__main__":
NoSQL_Project = Database_Project()
NoSQL_Project.title("NoSQL Database Project")
NoSQL_Project.maxsize(500, 500)
NoSQL_Project.mainloop()
I am creating a planning app and I want it to be personalized by having a title that says [Name]'s Planner. The user can enter their name into a text entry widget, press Submit, and then it will be displayed in the label. My application also has multiple pages, so the text entry will be on the start page and the label will be on the home page.
I have named the text entry widget nameentry and have created a function that takes the data from nameentry and displays it in the label name_label, however, I am getting an error message when I try to call the function by clicking the Submit button which says NameError: name 'nameentry' is not defined.
I am confused as I believe I have already defined nameentry by saying it equals the text entry widget.
import calendar
import tkinter as tk
from tkinter import ttk
from tkcalendar import *
from datetime import datetime
#calendar and display in label
#window = Tk()
#window.title("StudyFriendO")
LARGE_FONT= ("Verdana", 24)
class StudyFriendO(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("StudyFriendO") #naming window title
self.geometry('850x830') #size of window
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, HomePage, ToDoPage, TimetablePage): #list of multiple frames of program
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()
def set_date(self, cont):
#frame: StartPage = self.frames[cont]
#frame.date_label.config(text="Today's date is " + datetime.today().strftime("%B %d, %Y")) #function to get date from
frame2: HomePage = self.frames[HomePage]
frame2.date_label.config(text= datetime.today().strftime("%B %d, %Y")) #function to get date from
def getname(self, cont): #FUNCTION WHICH GRABS NAME FROM TEXT ENTRY
frame2: HomePage = self.frames[HomePage]
frame2.name_label.configure(text=nameentry.get() + "'s Planner ")
class StartPage(tk.Frame): #creating start page
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="StudyFriendO", font = LARGE_FONT, bg="#f2fcff")
label.pack(fill="x")
#place(x=315,y=100)
photo1 = tk.PhotoImage(file='apple.png') #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo1)
panel.image = photo1
panel.pack(fill="x")
#place(x=270,y=150)
label2 = tk.Label(self, text="Enter today's date and your first name below:", bg="#f2fcff")
label2.pack(fill="x", ipady=20)
#place(x=305, y=400)
cal = Calendar(self, background="#e0f6fc", disabledbackground="white", bordercolor="light blue", headersbackground="light blue", normalbackground="#e0f6fc", foreground="black", normalforeground='black', headersforeground='white', selectmode="day", year=2021, month=8, day=9)
cal.place(relx=0.5, rely=0.5, anchor='center')
#(x=300,y=430) #calendar
#TEXT ENTRY WHERE PERSON INPUTS NAME
nameentry = tk.Entry(self, width=20, bg="white") #text input for users name
nameentry.place(relx=0.5, rely=0.68, anchor='center')
#(x=365, y=635)
caldate = ttk.Button(self, text="Submit",
command=lambda: controller.set_date(StartPage)) #button to get current date
caldate.place(relx=0.5, rely=0.63, anchor='center')
button1 = ttk.Button(self, text="Enter",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(relx=0.5, rely=0.73, anchor='center')
#(x=387,y=660)
#BUTTON WHICH CALLS FUNCTION WHICH GRABS NAME (CURRENTLY LOCATED IN WEIRD LOCATION)
namebutton = ttk.Button(self, text="Submit", command=lambda: controller.getname(StartPage))
namebutton.place(relx=0.5, y=60)
#self.date_label = tk.Label(self, text="") #label to display date
#self.date_label.pack(pady=20)
self.configure(bg='#f2fcff')
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#label = tk.Label(self, text="Home", font = LARGE_FONT)
#label.pack(pady=10,padx=10)
#width of x
frame = tk.Frame(self, bg="#c0e3ed", height=110)
frame.pack(fill="x")
#LABEL WHICH DISPLAYS NAME FROM TEXT ENTRY
#tk.Label(self, text ="Name's Planner", fg="white", bg="#c0e3ed", font = LARGE_FONT).place(relx=0.5, y=50, anchor='center')
self.name_label = tk.Label(self, text="", font=("Arial Bold", 50))
self.name_label.place(x=0, y=0)
self.date_label = tk.Label(self, text="", bg="#c0e3ed")
# keep placing the label at top right corner
self.date_label.place(relx=1, y=0, anchor='ne')
#pack(side='top', anchor='ne')
#height of Y
tk.Label(self, text="", fg="white", bg="#99cbd8").pack(side="left", fill="y", ipadx=73)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Home", command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(x=35, y=145)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="To Do", command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.place(x=35, y=225)
#(relx=0.2, rely=0.4, anchor='center')
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Timetable", command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.place(x=35, y=305)
photo2 = tk.PhotoImage(file='apple.png') #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo2)
panel.image = photo2
panel.place(x=35, y=400)
self.configure(bg='#f7f6f6')
class ToDoPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="To Do", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
class TimetablePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Timetable", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
app = StudyFriendO()
app.mainloop()
The problem is happening because you're trying to reference a variable that's local to one method of one page on another. In an app with this architecture, a good way to share data among the Page class instances is through the controller argument they are all passed when they're created, which in this case is the StudyFriendO class instance.
Since you may have more than one variable to share as you develop your app, I've added a shared_data dictionary attribute and initialized with a tk.StringVar associated with the key 'name'. It is used as the textvariable= option when creating the tk.Entry widget on the StartPage and then also by the getname() method of the StudyFriendO controller. Using a StringVar allows the dictionary item to be defined before the Entry widget using it is created. After that happens (i.e. the StartPage instance is created) the current value of the Entry can be retrieved indirectly through it instead of the widget itself in the getname() method. You can easily add more variables in the future should you need them.
Below is your code with the modifications described. I've indicated where the changes are with #### comments to make them standout.
import calendar
import tkinter as tk
from tkinter import ttk
from tkcalendar import *
from datetime import datetime
#calendar and display in label
#window = Tk()
#window.title("StudyFriendO")
IMAGE_PATH = 'apple.png'
LARGE_FONT= ("Verdana", 24)
class StudyFriendO(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("StudyFriendO") #naming window title
self.geometry('850x830') #size of window
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
#### ADDED
self.shared_data = { # Variables shared by all pages.
'name': tk.StringVar(value='')
}
self.frames = {}
for F in (StartPage, HomePage, ToDoPage, TimetablePage): #list of multiple frames of program
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()
def set_date(self, cont):
#frame: StartPage = self.frames[cont]
#frame.date_label.config(text="Today's date is " + datetime.today().strftime("%B %d, %Y")) #function to get date from
frame2: HomePage = self.frames[HomePage]
frame2.date_label.config(text= datetime.today().strftime("%B %d, %Y")) #function to get date from
def getname(self, cont): #FUNCTION WHICH GRABS NAME FROM TEXT ENTRY
frame2: HomePage = self.frames[HomePage]
#### frame2.name_label.configure(text=nameentry.get() + "'s Planner ")
frame2.name_label.configure(text=self.shared_data['name'].get() + "'s Planner ")
class StartPage(tk.Frame): #creating start page
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="StudyFriendO", font = LARGE_FONT, bg="#f2fcff")
label.pack(fill="x")
#place(x=315,y=100)
photo1 = tk.PhotoImage(file=IMAGE_PATH) #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo1)
panel.image = photo1
panel.pack(fill="x")
#place(x=270,y=150)
label2 = tk.Label(self, text="Enter today's date and your first name below:", bg="#f2fcff")
label2.pack(fill="x", ipady=20)
#place(x=305, y=400)
cal = Calendar(self, background="#e0f6fc", disabledbackground="white", bordercolor="light blue", headersbackground="light blue", normalbackground="#e0f6fc", foreground="black", normalforeground='black', headersforeground='white', selectmode="day", year=2021, month=8, day=9)
cal.place(relx=0.5, rely=0.5, anchor='center')
#(x=300,y=430) #calendar
#TEXT ENTRY WHERE PERSON INPUTS NAME
#### nameentry = tk.Entry(self, width=20, bg="white") #text input for users name
nameentry = tk.Entry(self, width=20, bg="white", #text input for users name
textvariable=controller.shared_data['name'])
nameentry.place(relx=0.5, rely=0.68, anchor='center')
#(x=365, y=635)
caldate = ttk.Button(self, text="Submit",
command=lambda: controller.set_date(StartPage)) #button to get current date
caldate.place(relx=0.5, rely=0.63, anchor='center')
button1 = ttk.Button(self, text="Enter",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(relx=0.5, rely=0.73, anchor='center')
#(x=387,y=660)
#BUTTON WHICH CALLS FUNCTION WHICH GRABS NAME (CURRENTLY LOCATED IN WEIRD LOCATION)
namebutton = ttk.Button(self, text="Submit", command=lambda: controller.getname(StartPage))
namebutton.place(relx=0.5, y=60)
#self.date_label = tk.Label(self, text="") #label to display date
#self.date_label.pack(pady=20)
self.configure(bg='#f2fcff')
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#label = tk.Label(self, text="Home", font = LARGE_FONT)
#label.pack(pady=10,padx=10)
#width of x
frame = tk.Frame(self, bg="#c0e3ed", height=110)
frame.pack(fill="x")
#LABEL WHICH DISPLAYS NAME FROM TEXT ENTRY
#tk.Label(self, text ="Name's Planner", fg="white", bg="#c0e3ed", font = LARGE_FONT).place(relx=0.5, y=50, anchor='center')
self.name_label = tk.Label(self, text="", font=("Arial Bold", 50))
self.name_label.place(x=0, y=0)
self.date_label = tk.Label(self, text="", bg="#c0e3ed")
# keep placing the label at top right corner
self.date_label.place(relx=1, y=0, anchor='ne')
#pack(side='top', anchor='ne')
#height of Y
tk.Label(self, text="", fg="white", bg="#99cbd8").pack(side="left", fill="y", ipadx=73)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Home", command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(x=35, y=145)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="To Do", command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.place(x=35, y=225)
#(relx=0.2, rely=0.4, anchor='center')
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Timetable", command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.place(x=35, y=305)
photo2 = tk.PhotoImage(file=IMAGE_PATH) #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo2)
panel.image = photo2
panel.place(x=35, y=400)
self.configure(bg='#f7f6f6')
class ToDoPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="To Do", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
class TimetablePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Timetable", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
app = StudyFriendO()
app.mainloop()
I am working on creating a Tkinter planner application that has multiple pages. On the start page, you can enter a date in the calendar and press the 'enter' button to enter the application.
The home page then displays the date in the top right corner. Is there any way for the date label to overlap with the blue banner so that there isn't a grey line at the top? The date also needs to be placed so that it stays in the same spot even when the window is resized, hence why I have used the pack function. However, I believe that the pack function cannot overlap with other labels.
import calendar
import tkinter as tk
from tkinter import ttk
from tkcalendar import *
from datetime import datetime
#calendar and display in label
#window = Tk()
#window.title("StudyFriendO")
LARGE_FONT= ("Verdana", 24)
class StudyFriendO(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("StudyFriendO") #naming window title
self.geometry('850x830') #size of window
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, HomePage, ToDoPage, TimetablePage): #list of multiple frames of program
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()
def set_date(self, cont):
#frame: StartPage = self.frames[cont]
#frame.date_label.config(text="Today's date is " + datetime.today().strftime("%B %d, %Y")) #function to get date from
frame2: HomePage = self.frames[HomePage]
frame2.date_label.config(text= datetime.today().strftime("%B %d, %Y")) #function to get date from
class StartPage(tk.Frame): #creating start page
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="StudyFriendO", font = LARGE_FONT, bg="#f2fcff")
label.pack(fill="x")
#place(x=315,y=100)
photo1 = tk.PhotoImage(file=image file) #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo1)
panel.image = photo1
panel.pack(fill="x")
#place(x=270,y=150)
label2 = tk.Label(self, text="Enter today's date and your first name below:", bg="#f2fcff")
label2.pack(fill="x", ipady=20)
#place(x=305, y=400)
cal = Calendar(self, background="#e0f6fc", disabledbackground="white", bordercolor="light blue", headersbackground="light blue", normalbackground="#e0f6fc", foreground="black", normalforeground='black', headersforeground='white', selectmode="day", year=2021, month=8, day=9)
cal.place(relx=0.5, rely=0.5, anchor='center')
#(x=300,y=430) #calendar
nameentry = tk.Entry(self, width=20, bg="white") #text input for users name
nameentry.place(relx=0.5, rely=0.68, anchor='center')
#(x=365, y=635)
caldate = ttk.Button(self, text="Submit",
command=lambda: controller.set_date(StartPage)) #button to get current date
caldate.place(relx=0.5, rely=0.63, anchor='center')
button1 = ttk.Button(self, text="Enter",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(relx=0.5, rely=0.73, anchor='center')
#(x=387,y=660)
#self.date_label = tk.Label(self, text="") #label to display date
#self.date_label.pack(pady=20)
self.configure(bg='#f2fcff')
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#label = tk.Label(self, text="Home", font = LARGE_FONT)
#label.pack(pady=10,padx=10)
self.date_label = tk.Label(self, text="") #label to display date
self.date_label.pack(side='top', anchor='ne')
#width of x
tk.Label(self, text ="Name's Planner", fg="white", bg="#c0e3ed", font = LARGE_FONT).pack(fill="x", ipady=30)
#height of Y
tk.Label(self, text="", fg="white", bg="#99cbd8").pack(side="left", fill="y", ipadx=73)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Home", command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.place(x=35, y=145)
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="To Do", command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.place(x=35, y=225)
#(relx=0.2, rely=0.4, anchor='center')
button1 = tk.Button(self, height=2, width=10, bg="#e0f6fc", text="Timetable", command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.place(x=35, y=305)
photo2 = tk.PhotoImage(image file) #photo1 is a variable
#label (window, image=photo1, bg="black") .grid(row=0, column=0, sticky=E)
panel = tk.Label(self, image = photo2)
panel.image = photo2
panel.place(x=35, y=400)
self.configure(bg='#f7f6f6')
class ToDoPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="To Do", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
class TimetablePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Timetable", font = LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Home",
command=lambda: controller.show_frame(HomePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="Timetable",
command=lambda: controller.show_frame(TimetablePage)) #button to navigate page
button1.pack()
button1 = ttk.Button(self, text="To Do",
command=lambda: controller.show_frame(ToDoPage)) #button to navigate page
button1.pack()
app = StudyFriendO()
app.mainloop()
You can use .place() instead of .pack(), but better create and place it after the banner:
...
tk.Label(self, text ="Name's Planner", fg="white", bg="#c0e3ed", font = LARGE_FONT).pack(fill="x", ipady=30)
#label to display date with same background color of the above banner
self.date_label = tk.Label(self, text="", bg="#c0e3ed")
# keep placing the label at top right corner
self.date_label.place(relx=1, y=0, anchor='ne')
...
I am having a similar issue with the Shop class too. My first button (Teapops) is where I want all my buttons on my Home window and Shop window to be (except for Back to Home) if I use:
button1.pack(side=TOP, anchor=NW, padx=10, pady=60, expand=NO)
button2.pack(side=TOP, anchor=NW, padx=30, pady=60, expand=NO)
button3.pack(side=TOP, anchor=NW, padx=60, pady=60, expand=NO)
But then all the others appear lower and lower and I don't have any idea why except maybe I have an issue with my frames?
If I use this,
button1.pack(side=LEFT, anchor=NW, fill=BOTH, expand=1)
button2.pack(side=LEFT, anchor=NW, fill=BOTH, expand=1)
button3.pack(side=LEFT, anchor=NW, fill=BOTH, expand=1)
then all my buttons appear side by side but in the middle of the screen again like on my Home screen:
Can someone please explain to me whats going on? I think there are some basics about Frames that I am not understanding. Please help!!!!
import Tkinter as tk
from Tkinter import *
TITLE_FONT = (“Helvetica”, 18, “bold”)
CREDITS_FONT = (“Helvetica”, 12, “bold”)
class App(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 (Home, My_Plnts, Jrnl, Shop, Mail):
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(“Home”)
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class Home(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Home.configure(self, background=’#ade5ad’)
label = tk.Label(self, text=“Welcome Home, Maebert!”, background=’#ade5ad’, font=TITLE_FONT)
label.pack(side=“top”, fill=“x”, pady=10)
button1 = tk.Button(self, text=“My Plnts”,
command=lambda: controller.show_frame(“My_Plnts”))
button2 = tk.Button(self, text=“Jrnl”,
command=lambda: controller.show_frame(“Jrnl”))
button3 = tk.Button(self, text=“Shop”,
command=lambda: controller.show_frame(“Shop”))
button4 = tk.Button(self, text=“Mail”,
command=lambda: controller.show_frame(“Mail”))
button1.pack(side=LEFT, padx=60)
button2.pack(side=LEFT, padx=60)
button3.pack(side=LEFT, padx=60)
button4.pack(side=LEFT, padx=60)
class My_Plnts(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
My_Plnts.configure(self, background=’#ade5ad’)
label = tk.Label(self, text=“My Plnts”, background=’#ade5ad’, font=TITLE_FONT)
label.pack(side=“top”, anchor=NW, fill=“x”, pady=10)
button = tk.Button(self, text=“Back to Home”,
command=lambda: controller.show_frame(“Home”))
button.pack(side=“top”, anchor=NE)
class Jrnl(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Jrnl.configure(self, background=’#ade5ad’)
label = tk.Label(self, text=“Jrnl”, background=’#ade5ad’, font=TITLE_FONT)
label.pack(side=“top”, fill=“x”, pady=10)
button = tk.Button(self, text=“Back to Home”,
command=lambda: controller.show_frame(“Home”))
button.pack(side=“top”, anchor=NE)
class Shop(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Shop.configure(self, background=’#ade5ad’)
label = tk.Label(self, text=“Shop”, background=’#ade5ad’, font=TITLE_FONT)
label.pack(side=“top”, fill=“x”, pady=10)
label = tk.Label(self, text=“More at www.gfc.com”, background=’#ade5ad’, font=CREDITS_FONT)
label.pack(side=“bottom”, fill=“x”, pady=10)
button = tk.Button(self, text=“Back to Home”,
command=lambda: controller.show_frame(“Home”))
button1 = tk.Button(self, text=“Teapops”,
command=lambda: controller.show_frame(“Teapops”))
button2 = tk.Button(self, text=“Plants”,
command=lambda: controller.show_frame(“Plants”))
button3 = tk.Button(self, text=“Nail Polish”,
command=lambda: controller.show_frame(“Nail_Polish”))
button.pack(side=“top”, anchor=NE)
button1.pack(side=LEFT, anchor=NW, fill=BOTH, expand=1)
button2.pack(side=LEFT, anchor=NW, fill=BOTH, expand=1)
button3.pack(side=LEFT, anchor=NW, fill=BOTH, expand=1)
“”“
button1.pack(side=TOP, anchor=NW, padx=10, pady=60, expand=NO)
button2.pack(side=TOP, anchor=NW, padx=30, pady=60, expand=NO)
button3.pack(side=TOP, anchor=NW, padx=60, pady=60, expand=NO)
”“”
class Mail(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Mail.configure(self, background=’#ade5ad’)
label = tk.Label(self, text=“Mail”, background=’#ade5ad’, font=TITLE_FONT)
label.pack(side=“top”, fill=“x”, pady=10)
button = tk.Button(self, text=“Back to Home”,
command=lambda: controller.show_frame(“Home”))
button.pack(side=“top”, anchor=NE)
if __name__ == “__main__”:
app = App()
app.minsize(300,300)
app.geometry(“800x800”)
app.mainloop()
I built the below program to demonstrate to you how the .pack() method works, please feel free to play around with the different options and see how each affects the output:
from tkinter import *
root = Tk()
top = Toplevel()
top.withdraw()
var1 = StringVar(root)
var1.set("top")
var2 = StringVar(root)
var2.set("none")
var4 = StringVar(root)
var4.set("center")
var3 = BooleanVar(root)
def command(top, var1, var3, var2):
top.destroy()
top = Toplevel()
top.geometry("500x500")
Label(top, text="Welcome home").pack()
Button(top, text="Button1").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())
Button(top, text="Button2").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())
Button(top, text="Button3").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())
Button(top, text="Button4").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())
option1 = OptionMenu(root, var1, "top", "left", "bottom", "right")
check1 = Checkbutton(root, variable=var3, text="Expand?")
option2 = OptionMenu(root, var2, "none", "x", "y", "both")
option3 = OptionMenu(root, var4, "center", "n", "ne", "e", "se", "s", "sw", "w", "nw")
button1 = Button(root, text="Render", command=lambda:command(top, var1, var3, var2))
option1.pack()
check1.pack()
option2.pack()
option3.pack()
button1.pack()
root.mainloop()
This should show you how the different options affect the results of the .pack().
More to the point I believe the effect you are looking for can be achieved using .pack(side="left", expand="true", fill="x", anchor="n").
I am creating a little app that will take in details from the user about a bank transaction and then display it in a table.
I am currently using a CSV file to store the data and then when a new piece of data is put in, it will display that too.
I have a list of labels and then a button at the bottom of them to submit new entry. The problem I am getting is when the length of the table exceeds what it was to begin with there is a display error.
class accountant(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
master.title("Accountant")
self.pack()
self.numIncoming = 0
self.numOutgoing = 0
self.incoming = fs.fileStore("incoming", "csv")
print("log: incoming.csv opened sucessfully")
self.outgoing = fs.fileStore("outgoing", "csv")
print("log: outgoing.csv opened sucessfully")
self.setup()
def setup(self):
self.paint()
self.incomingData()
self.outgoingData()
self.newEntryButtons()
def paint(self):
tk.Label(self, width=45, text="incoming").grid(row=1, column=0, columnspan=45)
tk.Label(self, width=45, text="outgoing").grid(row=1, column=45, columnspan=45)
tk.Label(self, width=15, text="Date").grid(row=2, column=0, columnspan=15)
tk.Label(self, width=15, text="Transaction Name").grid(row=2, column=15, columnspan=15)
tk.Label(self, width=15, text="Amount").grid(row=2, column=30, columnspan=15)
tk.Label(self, width=15, text="Date").grid(row=2, column=45, columnspan=15)
tk.Label(self, width=15, text="Transaction Name").grid(row=2, column=60, columnspan=15)
tk.Label(self, width=15, text="Amount").grid(row=2, column=75, columnspan=15)
def incomingData(self):
self.incoming.closeFile()
self.incoming.openFile()
i = 3
for cell in self.incoming.reader:
#cell[0] = Date, cell[1]= Transaction Name, cell[2] =amount
tk.Label(self, width=15, text=cell[0]).grid(row=i, column=0, columnspan=15)
tk.Label(self, width=15, text=cell[1]).grid(row=i, column=15, columnspan=15)
tk.Label(self, width=15, text=cell[2]).grid(row=i, column=30, columnspan=15)
i += 1
self.numIncoming = i
print("incoming:", self.numIncoming-3)
print("outgoing:", self.numOutgoing-3)
def outgoingData(self):
self.outgoing.closeFile()
self.outgoing.openFile()
i = 3
for cell in self.outgoing.reader:
#cell[0] = Date, cell[1]= Transaction Name, cell[2] =amount
tk.Label(self, width=15, text=cell[0]).grid(row=i, column=45, columnspan=15)
tk.Label(self, width=15, text=cell[1]).grid(row=i, column=60, columnspan=15)
tk.Label(self, width=15, text=cell[2]).grid(row=i, column=75, columnspan=15)
i += 1
self.numOutgoing = i
print("incoming:", self.numIncoming-3)
print("outgoing:", self.numOutgoing-3, '\n\n')
def newEntryButtons(self):
if(self.numIncoming < self.numOutgoing):
tk.Button(self, text="new incoming", width=45, command=lambda: self.newEntry(self.incoming)).grid(row=self.numOutgoing, column=0, columnspan=45)
tk.Button(self, text="new outgoing", width=45, command=lambda: self.newEntry(self.outgoing)).grid(row=self.numOutgoing, column=45, columnspan=45)
else:
tk.Button(self, text="new incoming", width=45, command=lambda: self.newEntry(self.incoming)).grid(row=self.numIncoming, column=0, columnspan=45)
tk.Button(self, text="new outgoing", width=45, command=lambda: self.newEntry(self.outgoing)).grid(row=self.numIncoming, column=45, columnspan=45)
def newEntry(self, inFile):
win = tk.Toplevel()
self.newName = tk.StringVar()
self.newDate = tk.StringVar()
self.newAmount = tk.StringVar()
tk.Label(win, width=5, text="Name:").grid(row=0, column=0, columnspan=5)
tk.Entry(win, textvariable=self.newName).grid(row=0, column=5, columnspan=5)
tk.Label(win, width=5, text="date:").grid(row=1, column=0, columnspan=5)
tk.Entry(win, textvariable = self.newDate).grid(row=1, column=5, columnspan=5)
tk.Label(win, width=5, text="amount: £").grid(row=2, column=0, columnspan=5)
tk.Entry(win, textvariable=self.newAmount).grid(row=2, column=5, columnspan=5)
button = tk.Button(win, text="submit", width=5, command= lambda: self.submit(win, inFile))
button.grid(row=5, column=5, columnspan=5)
def submit(self, win, inFile):
with open(inFile.file, 'a') as f:
string= '\n'+self.newName.get() + ',' + self.newDate.get() + ',' + self.newAmount.get()
f.write(string)
if inFile.fileName == "incoming":
self.numIncoming += 1
# print("incoming:", self.numIncoming-3)
# print("outgoing:", self.numOutgoing-3)
else:
self.numOutgoing += 1
print("outgoing:", self.numOutgoing-3)
win.destroy()
self.setup()
filestore is just a class that basically opens the csv using
reader = csv.reader(open(file+'.'fileExt)) where file and fileExt are the parameters passed in.
Here is the image after a new entry. the bottom two buttons should stay as they are and the top two should be d e f in the left column and just whitespace in the right column
Replace self.pack() with self.grid(). To change a Label to Button you will, in addition, have to define a command function that executes when the Button is pressed, see the code below
bttn = tk.Button(self, text = "buttontitle", command = self.do_function )
bttn.grid(row = 14, column = 4, sticky = W)
def do_function():
print "HI"