I am working on a Python Tkinter application which is expected to have multiple windows. At the same time, I would like to keep certain layout (background image, Top/bottom labels) constant. I have tried to set the background image (b_image) and top left label (topleft_label ) but it's not showing up. Can someone look at this snippet and advise how to achieve this?
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
HEIGHT = 768
WIDTH = 1024
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("Sales System") # set the title of the main window
self.geometry("%dx%d+0+0" % (WIDTH, HEIGHT)) # set size of the main window to 300x300 pixels
container = tk.Frame(self)
b_image = tk.PhotoImage(file='background.png')
b_label = tk.Label(container, image=b_image)
b_label.place(relwidth=1, relheight=1)
topleft_label = tk.Label(container, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')
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")
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)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
app = MainApp()
app.mainloop()
The best way of going about this is most likely be to make a base_frame
class, which contains the image and the topleft_label
, "Welcome - Login Screen". This means the StartPage
object can inherit the background image from the base_frame
class.
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
HEIGHT = 768
WIDTH = 1366
class MainApp():
def __init__(self, master):
self.master = master
self.master.title("Sales System")
self.master.geometry("%dx%d+0+0" % (WIDTH, HEIGHT))
self.frames = {}
start_page = StartPage(master)
self.frames[StartPage] = start_page
start_page.grid(row=0, column=0, sticky="nsew")
self.master.grid_rowconfigure(0, weight=1)
self.master.grid_columnconfigure(0, weight=1)
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class base_frame(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(master, *args, **kwargs)
b_image = tk.PhotoImage(file='background.png')
b_label = tk.Label(self, image=b_image)
b_label.image = b_image
b_label.place(x=0, y=0, relwidth=1, relheight=1)
topleft_label = tk.Label(self, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')
class StartPage(base_frame):
def __init__(self, parent):
super().__init__(self, parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
def main():
root = tk.Tk() # MainApp()
main_app = MainApp(root)
root.mainloop()
if __name__ == '__main__':
main()
The piece of code that makes this class system run is like so:
def main():
root = tk.Tk() # MainApp()
main_app = MainApp(root)
root.mainloop()
if __name__ == '__main__':
main()
The line if __name__ == '__main__':
, in English, roughly translates too: If the program is run and not imported. So, if the program is run and not imported, run the main function.
root = tk.Tk()
simply creates a Tk window inside of the root variable.
main_app = MainApp(root)
initializes the main_app object with its master being the root variable
root.mainloop()
starts the tkinter loop.
The MainApp Class starts by setting its title to "Sales System" and resetting the geometry to the values defined in HEIGHT & WIDTH:
self.master = master
self.master.title("Sales System")
self.master.geometry("%dx%d+0+0" % (WIDTH, HEIGHT))
Then the self.frames
dictionary & the start_page
is initialized and the start_page
is placed in self.frames
:
self.frames = {}
start_page = StartPage(master)
self.frames[StartPage] = start_page
The start_page is then set to fill the whole of the window:
start_page.grid(row=0, column=0, sticky="nsew")
self.master.grid_rowconfigure(0, weight=1)
self.master.grid_columnconfigure(0, weight=1)
We then show the first page:
self.show_frame(StartPage)
The show_frame
function is then created
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
The first 3 lines creates a class which takes values the same as a tk.Frame
object does, with args and key word args passed through:
class base_frame(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(master, *args, **kwargs)
Then the image label is created:
b_image = tk.PhotoImage(file='background.png')
b_label = tk.Label(self, image=b_image)
b_label.image = b_image
b_label.place(x=0, y=0, relwidth=1, relheight=1)
The b_label.image = b_image
line is used to make sure the image is shown by the label (this is required when loading from within a function).
We then create the default topleft_label
:
topleft_label = tk.Label(self, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')
You may wish to update this code for these labels to be changed in the future, to do this simply replace topleft_label
with self.topleft_label
and b_label
with self.b_label
This class is not much different to the class you created previously:
class StartPage(base_frame):
def __init__(self, parent):
super().__init__(self, parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
The only difference being instead of inheriting from tk.Frame
, it inherits from the base_frame
class.