0

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 :)

5
  • 1
    It is better to provide a minimal reproducible example and the full error traceback. Commented Dec 9, 2022 at 5:04
  • @acw1668 added what I have so far, dont have any errors as i'm unsure on how to approach the problem - ty Commented Dec 9, 2022 at 5:14
  • 1
    You have said "its throwing me some errors (specifically an error about a master not being defined)" in your question. Also when running posted code, I get exception: NameError: name 'Page1' is not defined. Commented Dec 9, 2022 at 5:18
  • @acw1668 understood - i've edited the code to reproduce the master error i was getting before - Just for clarification, I was trying to apply the solution from the below thread stackoverflow.com/questions/14817210/… but the solution is for tkinter, and i'm trying to work with customtkinter Thank you Commented Dec 9, 2022 at 5:28
  • 1
    See question "Switch between two frames in tkinter?". The logic is the same whether tkinter Frame or CTkFrame is used. The solution of the question in your comment should also work on CTkFrame. Commented Dec 9, 2022 at 5:39

2 Answers 2

1

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()
Sign up to request clarification or add additional context in comments.

Comments

1

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()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.