I feel like my question is pretty straightforward, but I just cant seem to figure out how to do this. I'm currently creating a GUI project with CustomTkInter and trying to make a button that navigates through to the next page, but I'm not sure how to do this? I'm trying to link different pages together, essentially just trying to have a multi-page project, I've tried to apply the solution for the normal tkinter to my customtkinter - but its not worked so far and its throwing me some errors (specifically an error about a master not being defined)
This is what I have so far
import tkinter
import tkinter.messagebox
import customtkinter
from PIL import Image
import os
customtkinter.set_appearance_mode("Dark") # Modes: "System" (standard), "Dark", "Light"
customtkinter.set_default_color_theme("green") # Themes: "blue" (standard), "green", "dark-blue"
class Page(customtkinter.CTkFrame):
def __init__(self):
customtkinter.CTkFrame.__init__()
def show(self):
self.lift()
class Page1(Page):
def __init__(self):
Page.__init__()
class HomePage(customtkinter.CTkFrame):
def __init__(self):
super().__init__()
self.title("IMS")
self.geometry(f"{1300}x{800}")
self.rowconfigure((0), weight=1)
self.columnconfigure((0), weight=1)
self.rowconfigure((1, 2), weight=1)
self.columnconfigure((1,2), weight=1)
self.rowconfigure((3), weight=1)
image_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "images")
self.logoImage = customtkinter.CTkImage(Image.open(os.path.join(image_path, "logo.png")), size=(150, 66))
self.titleLogo = customtkinter.CTkLabel(master=self, text="", image=self.logoImage)
self.titleLogo.grid(row=0, column=1, padx=0, pady=0)
self.categoriesButton = customtkinter.CTkButton(master=self, border_width=2, text_color=("gray10", "#DCE4EE"),font=("",33), width=150, height=50, text="Categories", command=Page1.show())
self.categoriesButton.grid(row=2, column=0, padx=(50, 50), pady=(0, 40), sticky="nsew", columnspan=3)
if __name__ == "__main__":
app = HomePage()
app.mainloop()
Would appreciate any help, ty :)
CodePudding user response:
here's a great CTk doc that could help with your problem https://felipetesc.github.io/CtkDocs/#/multiple_frames
i made some minor changes because i was getting some error running sample 1 with python 3.9.13
import tkinter
import customtkinter
DARK_MODE = "dark"
customtkinter.set_appearance_mode(DARK_MODE)
customtkinter.set_default_color_theme("dark-blue")
class App(customtkinter.CTk):
frames = {"frame1": None, "frame2": None}
def frame1_selector(self):
App.frames["frame2"].pack_forget()
App.frames["frame1"].pack(in_=self.right_side_container,side=tkinter.TOP, fill=tkinter.BOTH, expand=True, padx=0, pady=0)
def frame2_selector(self):
App.frames["frame1"].pack_forget()
App.frames["frame2"].pack(in_=self.right_side_container,side=tkinter.TOP, fill=tkinter.BOTH, expand=True, padx=0, pady=0)
def __init__(self):
super().__init__()
# self.state('withdraw')
self.title("Change Frames")
self.geometry("{0}x{0} 0 0".format(self.winfo_screenwidth(), self.winfo_screenheight()))
# contains everything
main_container = customtkinter.CTkFrame(self)
main_container.pack(fill=tkinter.BOTH, expand=True, padx=10, pady=10)
# left side panel -> for frame selection
left_side_panel = customtkinter.CTkFrame(main_container, width=150)
left_side_panel.pack(side=tkinter.LEFT, fill=tkinter.Y, expand=False, padx=10, pady=10)
# buttons to select the frames
bt_frame1 = customtkinter.CTkButton(left_side_panel, text="Frame 1", command=self.frame1_selector)
bt_frame1.grid(row=0, column=0, padx=20, pady=10)
bt_frame2 = customtkinter.CTkButton(left_side_panel, text="Frame 2", command=self.frame2_selector)
bt_frame2.grid(row=1, column=0, padx=20, pady=10)
# right side panel -> to show the frame1 or frame 2
self.right_side_panel = customtkinter.CTkFrame(main_container)
self.right_side_panel.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=True, padx=10, pady=10)
self.right_side_container = customtkinter.CTkFrame(self.right_side_panel,fg_color="#000811")
self.right_side_container.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=True, padx=0, pady=0)
App.frames['frame1'] = customtkinter.CTkFrame(main_container,fg_color="red")
bt_from_frame1 = customtkinter.CTkButton(App.frames['frame1'], text="Test 1", command=lambda:print("test 1") )
bt_from_frame1.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER)
App.frames['frame2'] = customtkinter.CTkFrame(main_container,fg_color="blue")
bt_from_frame2 = customtkinter.CTkButton(App.frames['frame2'], text="Test 2", command=lambda:print("test 2") )
bt_from_frame2.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER)
a = App()
a.mainloop()
CodePudding user response:
i made a very basic template that you could use and modify as you want or just take the principle out of it.
import tkinter
import customtkinter
DARK_MODE = "dark"
customtkinter.set_appearance_mode(DARK_MODE)
customtkinter.set_default_color_theme("dark-blue")
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("Change Frames")
# remove title bar , page reducer and closing page !!!most have a quit button with app.destroy!!! (this app have a quit button so don't worry about that)
self.overrideredirect(True)
# make the app as big as the screen (no mater wich screen you use)
self.geometry("{0}x{1} 0 0".format(self.winfo_screenwidth(), self.winfo_screenheight()))
# root!
self.main_container = customtkinter.CTkFrame(self, corner_radius=10)
self.main_container.pack(fill=tkinter.BOTH, expand=True, padx=10, pady=10)
# left side panel -> for frame selection
self.left_side_panel = customtkinter.CTkFrame(self.main_container, width=150, corner_radius=10)
self.left_side_panel.pack(side=tkinter.LEFT, fill=tkinter.Y, expand=False, padx=5, pady=5)
self.left_side_panel.grid_columnconfigure(0, weight=1)
self.left_side_panel.grid_rowconfigure((0, 1, 2, 3), weight=0)
self.left_side_panel.grid_rowconfigure((4, 5), weight=1)
# self.left_side_panel WIDGET
self.logo_label = customtkinter.CTkLabel(self.left_side_panel, text="Welcome! \n", font=customtkinter.CTkFont(size=20, weight="bold"))
self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10))
self.scaling_label = customtkinter.CTkLabel(self.left_side_panel, text="UI Scaling:", anchor="w")
self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0))
self.scaling_optionemenu = customtkinter.CTkOptionMenu(self.left_side_panel, values=["80%", "90%", "100%", "110%", "120%"],
command=self.change_scaling_event)
self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20), sticky = "s")
self.bt_Quit = customtkinter.CTkButton(self.left_side_panel, text="Quit", fg_color= '#EA0000', hover_color = '#B20000', command= self.close_window)
self.bt_Quit.grid(row=9, column=0, padx=20, pady=10)
# button to select correct frame IN self.left_side_panel WIDGET
self.bt_dashboard = customtkinter.CTkButton(self.left_side_panel, text="Dashboard", command=self.dash)
self.bt_dashboard.grid(row=1, column=0, padx=20, pady=10)
self.bt_statement = customtkinter.CTkButton(self.left_side_panel, text="Statement", command=self.statement)
self.bt_statement.grid(row=2, column=0, padx=20, pady=10)
self.bt_categories = customtkinter.CTkButton(self.left_side_panel, text="Manage Categories", command=self.categories)
self.bt_categories.grid(row=3, column=0, padx=20, pady=10)
# right side panel -> have self.right_dashboard inside it
self.right_side_panel = customtkinter.CTkFrame(self.main_container, corner_radius=10, fg_color="#000811")
self.right_side_panel.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=True, padx=5, pady=5)
self.right_dashboard = customtkinter.CTkFrame(self.main_container, corner_radius=10, fg_color="#000811")
self.right_dashboard.pack(in_=self.right_side_panel, side=tkinter.TOP, fill=tkinter.BOTH, expand=True, padx=0, pady=0)
# self.right_dashboard ----> dashboard widget
def dash(self):
self.clear_frame()
self.bt_from_frame1 = customtkinter.CTkButton(self.right_dashboard, text="dash", command=lambda:print("test dash") )
self.bt_from_frame1.grid(row=0, column=0, padx=20, pady=(10, 0))
self.bt_from_frame2 = customtkinter.CTkButton(self.right_dashboard, text="dash 1", command=lambda:print("test dash 1" ) )
self.bt_from_frame2.grid(row=1, column=0, padx=20, pady=(10, 0))
# self.right_dashboard ----> statement widget
def statement(self):
self.clear_frame()
self.bt_from_frame3 = customtkinter.CTkButton(self.right_dashboard, text="statement", command=lambda:print("test statement") )
self.bt_from_frame3.grid(row=0, column=0, padx=20, pady=(10, 0))
# self.right_dashboard ----> categories widget
def categories(self):
self.clear_frame()
self.bt_from_frame4 = customtkinter.CTkButton(self.right_dashboard, text="categories", command=lambda:print("test cats") )
self.bt_from_frame4.grid(row=0, column=0, padx=20, pady=(10, 0))
# Change scaling of all widget 80% to 120%
def change_scaling_event(self, new_scaling: str):
new_scaling_float = int(new_scaling.replace("%", "")) / 100
customtkinter.set_widget_scaling(new_scaling_float)
# close the entire window
def close_window(self):
App.destroy(self)
# CLEAR ALL THE WIDGET FROM self.right_dashboard(frame) BEFORE loading the widget of the concerned page
def clear_frame(self):
for widget in self.right_dashboard.winfo_children():
widget.destroy()
a = App()
a.mainloop()