Skip to content

Multiple frames

Tom Schimansky edited this page Aug 16, 2022 · 1 revision

Widgets that belong together or create a specific functionality together should be placed in a frame, so that they can be separated in the code and that they visibly form a unit in the UI.

A frame should be created as a separate class, which also can be placed in a separate file or module. You can then simply create an instance of the frame in your main app class and place it on the window. Another big advantage is, that you can easily move the frame within the app window, because you don't need to change the positions of all the widgets inside the frame.

In the following I created a frame which implements a group of radio buttons with a label as a header. The class inherits from CTkFrame and will be extended by methods called get_value and set_value to get and set the current selected radio button string:

class RadioButtonFrame(customtkinter.CTkFrame):
    def __init__(self, *args, header_name="RadioButtonFrame", **kwargs):
        super().__init__(*args, **kwargs)
        
        self.header_name = header_name

        self.header = customtkinter.CTkLabel(self, text=self.header_name)
        self.header.grid(row=0, column=0, padx=10, pady=10)

        self.radio_button_var = customtkinter.StringVar(value="")

        self.radio_button_1 = customtkinter.CTkRadioButton(self, text="Option 1", value="Option 1", variable=self.radio_button_var)
        self.radio_button_1.grid(row=1, column=0, padx=10, pady=10)
        self.radio_button_2 = customtkinter.CTkRadioButton(self, text="Option 2", value="Option 2", variable=self.radio_button_var)
        self.radio_button_2.grid(row=2, column=0, padx=10, pady=10)
        self.radio_button_3 = customtkinter.CTkRadioButton(self, text="Option 3", value="Option 3", variable=self.radio_button_var)
        self.radio_button_3.grid(row=3, column=0, padx=10, pady=(10, 20))

    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)

This frame can now be placed on the app window by creating an instance of it, like you would do for a standard CTkFrame:

import customtkinter


class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        self.geometry("500x300")
        self.title("RadioButtonFrame test")

        self.radio_button_frame_1 = RadioButtonFrame(self, header_name="RadioButtonFrame 1")
        self.radio_button_frame_1.grid(row=0, column=0, padx=20, pady=20)

        self.frame_1_button = customtkinter.CTkButton(self, text="Print value of frame 1", command=self.print_value_frame_1)
        self.frame_1_button.grid(row=1, column=0, padx=20, pady=10)

    def print_value_frame_1(self):
        print(f"Frame 1 value: {self.radio_button_frame_1.get_value()}")


if __name__ == "__main__":
    app = App()
    app.mainloop()

I also added a button a connected a command to print the current value of the radio button frame 1 to the terminal. The window will look like the following: Bildschirmfoto 2022-08-16 um 12 49 42

And because the radio button frame is structured as a class, there can easily be created multiple instances of it, like in the following example:

import customtkinter


class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        self.geometry("500x300")
        self.title("RadioButtonFrame test")

        # create radio button frame 1 with print button
        self.radio_button_frame_1 = RadioButtonFrame(self, header_name="RadioButtonFrame 1")
        self.radio_button_frame_1.grid(row=0, column=0, padx=20, pady=20)

        self.frame_1_button = customtkinter.CTkButton(self, text="Print value of frame 1", command=self.print_value_frame_1)
        self.frame_1_button.grid(row=1, column=0, padx=20, pady=10)

        # create radio button frame 2 with print button
        self.radio_button_frame_2 = RadioButtonFrame(self, header_name="RadioButtonFrame 2")
        self.radio_button_frame_2.grid(row=0, column=1, padx=20, pady=20)

        self.frame_2_button = customtkinter.CTkButton(self, text="Print value of frame 2", command=self.print_value_frame_1)
        self.frame_2_button.grid(row=1, column=1, padx=20, pady=10)

    def print_value_frame_1(self):
        print(f"Frame 1 value: {self.radio_button_frame_1.get_value()}")

    def print_value_frame_2(self):
        print(f"Frame 2 value: {self.radio_button_frame_2.get_value()}")


if __name__ == "__main__":
    app = App()
    app.mainloop()
Bildschirmfoto 2022-08-16 um 12 54 25

Of course you could also add another attribute to the RadioButtonFrame class, so that you can not only customize the header_name, but also the values of the radio buttons.