diff --git a/app.py b/app.py index a083e4d..207c79a 100644 --- a/app.py +++ b/app.py @@ -1,40 +1,36 @@ import tkinter -import tkinter.messagebox import customtkinter -from elements.sidebar import sidebar - -# General Setup -customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light" -customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue" - +from frames import SidebarFrame, PersonFrame, VermögenFrame +# Main application class App(customtkinter.CTk): + def __init__(self): super().__init__() - - # configure window - self.title("BudgetPy") - self.geometry(f"{1100}x{580}") - - # configure grid layout (4x4) - self.grid_columnconfigure(1, weight=1) - self.grid_columnconfigure((2, 3), weight=0) - self.grid_rowconfigure((0, 1, 2), weight=1) + + #container to pack different windows of the app into + container = customtkinter.CTkFrame(self) + container.pack(expand=True, fill='both') + container.grid_rowconfigure(0, weight=1) + container.grid_columnconfigure(0, weight=1) + self.sidebar = SidebarFrame(container, self) + self.sidebar.grid(row=0, column=0, padx=20, pady=20) + + self.frames = {} + self.frames['personFrame'] = PersonFrame(container, self) + self.frames['vermögenFrame'] = VermögenFrame(container, self) + + for F in ('personFrame', 'vermögenFrame'): - # Load Elements - sidebar(self) + self.frames[F].grid(row = 0, column = 1, sticky='nsew') - #Events - def change_appearance_mode_event(self, new_appearance_mode: str): - customtkinter.set_appearance_mode(new_appearance_mode) - - def change_scaling_event(self, new_scaling: str): - new_scaling_float = int(new_scaling.replace("%", "")) / 100 - customtkinter.set_widget_scaling(new_scaling_float) + self.show_frame('personFrame') + + def show_frame(self, page_class): + frame = self.frames[page_class] + frame.tkraise() - def sidebar_button_event(self): - print("sidebar_button click") -if __name__ == "__main__": +if __name__ == '__main__': app = App() app.mainloop() \ No newline at end of file diff --git a/elements/__init__.py b/elements/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/elements/sidebar.py b/elements/sidebar.py deleted file mode 100644 index 19ddfbd..0000000 --- a/elements/sidebar.py +++ /dev/null @@ -1,52 +0,0 @@ -import tkinter -import tkinter.messagebox -import customtkinter - -# create sidebar frame with widgets -def sidebar(self): - self.sidebar_frame = customtkinter.CTkFrame(self, width=140, corner_radius=0) - self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") - self.sidebar_frame.grid_rowconfigure(9, weight=1) - # Logo - self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="BudgetPy", font=customtkinter.CTkFont(size=20, weight="bold")) - self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) - - # Button Personen - self.sidebar_button_1 = customtkinter.CTkButton(self.sidebar_frame, text="Personen", command=self.sidebar_button_event) - self.sidebar_button_1.grid(row=1, column=0, padx=20, pady=10) - # Button Vermögen - self.sidebar_button_2 = customtkinter.CTkButton(self.sidebar_frame, text="Vermögen", command=self.sidebar_button_event) - self.sidebar_button_2.grid(row=2, column=0, padx=20, pady=10) - # Button Projekte - self.sidebar_button_3 = customtkinter.CTkButton(self.sidebar_frame, text="Projekte", command=self.sidebar_button_event) - self.sidebar_button_3.grid(row=3, column=0, padx=20, pady=10) - # Button Kategorien - self.sidebar_button_4 = customtkinter.CTkButton(self.sidebar_frame, text="Kategorien", command=self.sidebar_button_event) - self.sidebar_button_4.grid(row=4, column=0, padx=20, pady=10) - # Button Einträge - self.sidebar_button_4 = customtkinter.CTkButton(self.sidebar_frame, text="Einträge", command=self.sidebar_button_event) - self.sidebar_button_4.grid(row=6, column=0, padx=20, pady=10) - # Button Übersicht - self.sidebar_button_5 = customtkinter.CTkButton(self.sidebar_frame, text="Übersicht", command=self.sidebar_button_event) - self.sidebar_button_5.grid(row=7, column=0, padx=20, pady=10) - # Button Export - self.sidebar_button_6 = customtkinter.CTkButton(self.sidebar_frame, text="Export", command=self.sidebar_button_event) - self.sidebar_button_6.grid(row=8, column=0, padx=20, pady=10) - - # Apperance Mode Label - self.appearance_mode_label = customtkinter.CTkLabel(self.sidebar_frame, text="Appearance Mode:", anchor="w") - self.appearance_mode_label.grid(row=10, column=0, padx=20, pady=(10, 0)) - # Apperance Mode Option Menu - self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["System", "Dark", "Light"], - command=self.change_appearance_mode_event) - self.appearance_mode_optionemenu.grid(row=11, column=0, padx=20, pady=(10, 10)) - - # UI Scaling Label - self.scaling_label = customtkinter.CTkLabel(self.sidebar_frame, text="UI Scaling:", anchor="w") - self.scaling_label.grid(row=12, column=0, padx=20, pady=(10, 0)) - # UI Scaling Option Menu - self.scaling_optionemenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["80%", "90%", "100%", "110%", "120%"], - command=self.change_scaling_event) - self.scaling_optionemenu.grid(row=13, column=0, padx=20, pady=(10, 20)) - - diff --git a/examples/switchFrames.py b/examples/switchFrames.py new file mode 100644 index 0000000..07f088c --- /dev/null +++ b/examples/switchFrames.py @@ -0,0 +1,138 @@ +import tkinter +import customtkinter + +# Main application +class App(customtkinter.CTk): + + def __init__(self): + super().__init__() + + #container to pack different windows of the app into + container = customtkinter.CTkFrame(self) + container.pack(expand=True, fill='both') + container.grid_rowconfigure(0, weight=1) + container.grid_columnconfigure(0, weight=1) + + self.frames = {} + self.frames['homescreen'] = HomeScreen(container, self) + self.frames['page_1'] = MainModes(container, self) + + for F in ('homescreen', 'page_1'): + + self.frames[F].grid(row = 0, column = 0, sticky='nsew') + + self.show_frame('homescreen') + + def show_frame(self, page_class): + frame = self.frames[page_class] + frame.tkraise() + +class HomeScreen(customtkinter.CTkFrame): + def __init__(self, parent, controller): + customtkinter.CTkFrame.__init__(self, parent) + + self.controller = controller + + #Configure rows and columns + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + + #Define buttons + page_1_button = customtkinter.CTkButton(self, + text="Page 1", + command=lambda: controller.show_frame('page_1')) + + #Position of buttons in the main_window + page_1_button.grid(row=0, column=0, sticky='nsew') + +class MainModes(customtkinter.CTkFrame): + def __init__(self, parent, controller): + customtkinter.CTkFrame.__init__(self, parent) + + self.controller = controller + + #overall layout + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) #mode_1 and mode_2 tabs are contained here + self.grid_rowconfigure(1, weight=1) #all widgets are contained in two frames in this row, clicking between mode_1 and mode_2 buttons raises different frames containing different widgets + self.grid_rowconfigure(2, weight=1) #back button is here + + self.frame = customtkinter.CTkFrame(self) #this frame contains the mode_1 and mode_2 frames and they are raised over one another according to which tab is selected + self.frame.grid_rowconfigure(0, weight=1) + self.frame.grid_columnconfigure(0, weight=1) + + #====================================Mode 1 Frame====================================# + + self.mode_1_frame = customtkinter.CTkFrame(self.frame) + + self.mode_1_frame.grid_columnconfigure(0, weight=1) + self.mode_1_frame.grid_rowconfigure(0, weight=1) + + self.mode_1_frame.grid(row=0, column=0, sticky='nsew') + + #====================================Mode 2 Frame====================================# + + self.mode_2_frame = customtkinter.CTkFrame(self.frame) + + self.mode_2_frame.grid_columnconfigure(0, weight=1) + self.mode_2_frame.grid_rowconfigure(0, weight=1) + + self.mode_2_frame.grid(row=0, column=0, sticky='nsew') + + #====================================Mode 1 Frame Widgets====================================# + + self.mode_1_switch_var = tkinter.StringVar(self.mode_1_frame) + self.mode_1_switch_var.set(value='Mode 1: ON') + + #function that sets the textvariable values of mode_1_switch and mode_2_switch when either is toggled + def switch_functions(switch_var, mode, switch): + switch_var.set(value=f'{mode}: ' + switch.get()) + + self.mode_1_switch = customtkinter.CTkSwitch(self.mode_1_frame, + textvariable=self.mode_1_switch_var, + onvalue='ON', + offvalue='OFF', + command=lambda: [switch_functions(self.mode_1_switch_var, 'Mode 1', self.mode_1_switch), self.mode_2_switch.toggle()]) + + self.mode_1_switch.select()#turns switch on at open + self.mode_1_switch.grid(row=0, column=0) + + #====================================Mode_2 Frame Widgets====================================# + + self.mode_2_switch_var = tkinter.StringVar(self.mode_2_frame) + self.mode_2_switch_var.set(value='Mode 2: OFF') + + + self.mode_2_switch = customtkinter.CTkSwitch(self.mode_2_frame, + textvariable=self.mode_2_switch_var, + onvalue='ON', + offvalue='OFF', + command=lambda: [switch_functions(self.mode_2_switch_var, 'Mode 2', self.mode_2_switch), self.mode_1_switch.toggle()]) + + self.mode_2_switch.grid(row=0, column=0) + + #====================================Frame toggle and back buttons====================================# + + self.mode_2_button = customtkinter.CTkButton(self, + text='Mode 2', + command=lambda: self.mode_2_frame.tkraise()) + + self.mode_1_button = customtkinter.CTkButton(self, + text = 'Mode 1', + command=lambda: self.mode_1_frame.tkraise()) + + self.back_button = customtkinter.CTkButton(self, + text='Back', + command=lambda: controller.show_frame('homescreen')) + + self.mode_1_button.grid(row=0, column=0, sticky='nsew') + self.mode_2_button.grid(row=0, column=1, sticky='nsew') + self.frame.grid(row=1, columnspan=2, sticky='nsew') + self.back_button.grid(row=2, column=0, columnspan=2, sticky='nsew') + + self.mode_1_frame.tkraise() + +if __name__ == '__main__': + app = App() + app.mainloop() \ No newline at end of file diff --git a/frames.py b/frames.py new file mode 100644 index 0000000..d7c5db1 --- /dev/null +++ b/frames.py @@ -0,0 +1,184 @@ +import tkinter +import tkinter.messagebox +import customtkinter + + +class VermögenFrame(customtkinter.CTkFrame): + def __init__(self, parent, controller, *args, **kwargs): + customtkinter.CTkFrame.__init__(self, parent) + #super().__init__(*args, **kwargs) + # create textbox + self.textbox = customtkinter.CTkTextbox(self, width=250) + self.textbox.grid(row=0, column=1, padx=(20, 0), pady=(20, 0), sticky="nsew") + + # set default values + self.textbox.insert("0.0", "CTkTextbox\n\n" + "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.\n\n" * 20) + +class PersonFrame(customtkinter.CTkFrame): + def __init__(self, parent, controller, *args, **kwargs): + customtkinter.CTkFrame.__init__(self, parent) + #super().__init__(*args, self, **kwargs) + # create main entry and button + self.entry = customtkinter.CTkEntry(self, placeholder_text="CTkEntry") + self.entry.grid(row=3, column=1, columnspan=2, padx=(20, 0), pady=(20, 20), sticky="nsew") + + self.main_button_1 = customtkinter.CTkButton(master=self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE")) + self.main_button_1.grid(row=3, column=3, padx=(20, 20), pady=(20, 20), sticky="nsew") + + # create textbox + self.textbox = customtkinter.CTkTextbox(self, width=250) + self.textbox.grid(row=0, column=1, padx=(20, 0), pady=(20, 0), sticky="nsew") + + # create tabview + self.tabview = customtkinter.CTkTabview(self, width=250) + self.tabview.grid(row=0, column=2, padx=(20, 0), pady=(20, 0), sticky="nsew") + self.tabview.add("CTkTabview") + self.tabview.add("Tab 2") + self.tabview.add("Tab 3") + self.tabview.tab("CTkTabview").grid_columnconfigure(0, weight=1) # configure grid of individual tabs + self.tabview.tab("Tab 2").grid_columnconfigure(0, weight=1) + + self.optionmenu_1 = customtkinter.CTkOptionMenu(self.tabview.tab("CTkTabview"), dynamic_resizing=False, + values=["Value 1", "Value 2", "Value Long Long Long"]) + self.optionmenu_1.grid(row=0, column=0, padx=20, pady=(20, 10)) + self.combobox_1 = customtkinter.CTkComboBox(self.tabview.tab("CTkTabview"), + values=["Value 1", "Value 2", "Value Long....."]) + self.combobox_1.grid(row=1, column=0, padx=20, pady=(10, 10)) + self.string_input_button = customtkinter.CTkButton(self.tabview.tab("CTkTabview"), text="Open CTkInputDialog", + command=self.open_input_dialog_event) + self.string_input_button.grid(row=2, column=0, padx=20, pady=(10, 10)) + self.label_tab_2 = customtkinter.CTkLabel(self.tabview.tab("Tab 2"), text="CTkLabel on Tab 2") + self.label_tab_2.grid(row=0, column=0, padx=20, pady=20) + + # create radiobutton frame + self.radiobutton_frame = customtkinter.CTkFrame(self) + self.radiobutton_frame.grid(row=0, column=3, padx=(20, 20), pady=(20, 0), sticky="nsew") + self.radio_var = tkinter.IntVar(value=0) + self.label_radio_group = customtkinter.CTkLabel(master=self.radiobutton_frame, text="CTkRadioButton Group:") + self.label_radio_group.grid(row=0, column=2, columnspan=1, padx=10, pady=10, sticky="") + self.radio_button_1 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=0) + self.radio_button_1.grid(row=1, column=2, pady=10, padx=20, sticky="n") + self.radio_button_2 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=1) + self.radio_button_2.grid(row=2, column=2, pady=10, padx=20, sticky="n") + self.radio_button_3 = customtkinter.CTkRadioButton(master=self.radiobutton_frame, variable=self.radio_var, value=2) + self.radio_button_3.grid(row=3, column=2, pady=10, padx=20, sticky="n") + + # create checkbox and switch frame + self.checkbox_slider_frame = customtkinter.CTkFrame(self) + self.checkbox_slider_frame.grid(row=1, column=3, padx=(20, 20), pady=(20, 0), sticky="nsew") + self.checkbox_1 = customtkinter.CTkCheckBox(master=self.checkbox_slider_frame) + self.checkbox_1.grid(row=1, column=0, pady=(20, 10), padx=20, sticky="n") + self.checkbox_2 = customtkinter.CTkCheckBox(master=self.checkbox_slider_frame) + self.checkbox_2.grid(row=2, column=0, pady=10, padx=20, sticky="n") + self.switch_1 = customtkinter.CTkSwitch(master=self.checkbox_slider_frame, command=lambda: print("switch 1 toggle")) + self.switch_1.grid(row=3, column=0, pady=10, padx=20, sticky="n") + self.switch_2 = customtkinter.CTkSwitch(master=self.checkbox_slider_frame) + self.switch_2.grid(row=4, column=0, pady=(10, 20), padx=20, sticky="n") + + # create slider and progressbar frame + self.slider_progressbar_frame = customtkinter.CTkFrame(self, fg_color="transparent") + self.slider_progressbar_frame.grid(row=1, column=1, columnspan=2, padx=(20, 0), pady=(20, 0), sticky="nsew") + self.slider_progressbar_frame.grid_columnconfigure(0, weight=1) + self.slider_progressbar_frame.grid_rowconfigure(4, weight=1) + self.seg_button_1 = customtkinter.CTkSegmentedButton(self.slider_progressbar_frame) + self.seg_button_1.grid(row=0, column=0, padx=(20, 10), pady=(10, 10), sticky="ew") + self.progressbar_1 = customtkinter.CTkProgressBar(self.slider_progressbar_frame) + self.progressbar_1.grid(row=1, column=0, padx=(20, 10), pady=(10, 10), sticky="ew") + self.progressbar_2 = customtkinter.CTkProgressBar(self.slider_progressbar_frame) + self.progressbar_2.grid(row=2, column=0, padx=(20, 10), pady=(10, 10), sticky="ew") + self.slider_1 = customtkinter.CTkSlider(self.slider_progressbar_frame, from_=0, to=1, number_of_steps=4) + self.slider_1.grid(row=3, column=0, padx=(20, 10), pady=(10, 10), sticky="ew") + self.slider_2 = customtkinter.CTkSlider(self.slider_progressbar_frame, orientation="vertical") + self.slider_2.grid(row=0, column=1, rowspan=5, padx=(10, 10), pady=(10, 10), sticky="ns") + self.progressbar_3 = customtkinter.CTkProgressBar(self.slider_progressbar_frame, orientation="vertical") + self.progressbar_3.grid(row=0, column=2, rowspan=5, padx=(10, 20), pady=(10, 10), sticky="ns") + + # set default values + self.checkbox_2.configure(state="disabled") + self.switch_2.configure(state="disabled") + self.checkbox_1.select() + self.switch_1.select() + self.radio_button_3.configure(state="disabled") + self.optionmenu_1.set("CTkOptionmenu") + self.combobox_1.set("CTkComboBox") + self.slider_1.configure(command=self.progressbar_2.set) + self.slider_2.configure(command=self.progressbar_3.set) + self.progressbar_1.configure(mode="indeterminnate") + self.progressbar_1.start() + self.textbox.insert("0.0", "CTkTextbox\n\n" + "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.\n\n" * 20) + self.seg_button_1.configure(values=["CTkSegmentedButton", "Value 2", "Value 3"]) + self.seg_button_1.set("Value 2") + + def open_input_dialog_event(self): + dialog = customtkinter.CTkInputDialog(text="Type in a number:", title="CTkInputDialog") + print("CTkInputDialog:", dialog.get_input()) + +class SidebarFrame(customtkinter.CTkFrame): + def __init__(self, parent, controller): + #super().__init__(*args, **kwargs) + customtkinter.CTkFrame.__init__(self, parent) + + self.sidebar_frame = customtkinter.CTkFrame(self, width=140, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + self.sidebar_frame.grid_rowconfigure(9, weight=1) + # Header + self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="BudgetPy", font=customtkinter.CTkFont(size=20, weight="bold")) + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) + # Button Personen + self.sidebar_button_1 = customtkinter.CTkButton(self.sidebar_frame, text="Personen", command=lambda: controller.show_frame('personFrame')) + self.sidebar_button_1.grid(row=1, column=0, padx=20, pady=10) + # Button Vermögen + self.sidebar_button_2 = customtkinter.CTkButton(self.sidebar_frame, text="Vermögen", command=lambda: controller.show_frame('vermögenFrame')) + self.sidebar_button_2.grid(row=2, column=0, padx=20, pady=10) + # Button Projekte + self.sidebar_button_3 = customtkinter.CTkButton(self.sidebar_frame, text="Projekte", command=self.sidebar_button_event) + self.sidebar_button_3.grid(row=3, column=0, padx=20, pady=10) + # Button Kategorien + self.sidebar_button_4 = customtkinter.CTkButton(self.sidebar_frame, text="Kategorien", command=self.sidebar_button_event) + self.sidebar_button_4.grid(row=4, column=0, padx=20, pady=10) + # Button Einträge + self.sidebar_button_4 = customtkinter.CTkButton(self.sidebar_frame, text="Einträge", command=self.sidebar_button_event) + self.sidebar_button_4.grid(row=6, column=0, padx=20, pady=10) + # Button Übersicht + self.sidebar_button_5 = customtkinter.CTkButton(self.sidebar_frame, text="Übersicht", command=self.sidebar_button_event) + self.sidebar_button_5.grid(row=7, column=0, padx=20, pady=10) + # Button Export + self.sidebar_button_6 = customtkinter.CTkButton(self.sidebar_frame, text="Export", command=self.sidebar_button_event) + self.sidebar_button_6.grid(row=8, column=0, padx=20, pady=10) + + # Apperance Mode Label + self.appearance_mode_label = customtkinter.CTkLabel(self.sidebar_frame, text="Theme:", anchor="w") + self.appearance_mode_label.grid(row=10, column=0, padx=20, pady=(10, 0)) + # Apperance Mode Option Menu + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["Light", "Dark", "System"], + command=self.change_appearance_mode_event) + # UI Scaling Label + self.scaling_label = customtkinter.CTkLabel(self.sidebar_frame, text="Skalierung:", anchor="w") + self.scaling_label.grid(row=12, column=0, padx=20, pady=(10, 0)) + # UI Scaling Option Menu + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=13, column=0, padx=20, pady=(10, 20)) + + # set default values + self.appearance_mode_optionemenu.grid(row=11, column=0, padx=20, pady=(10, 10)) + self.appearance_mode_optionemenu.set("System") + self.scaling_optionemenu.set("100%") + + def get_value(self): + """ returns selected value as a string, returns an empty string if nothing selected """ + return self.radio_button_var.get() + + def set_value(self, selection): + """ selects the corresponding radio button, selects nothing if no corresponding radio button """ + self.radio_button_var.set(selection) + + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + def sidebar_button_event(self): + print("sidebar_button click")