TomSchimansky / CustomTkinter

A modern and customizable python UI-library based on Tkinter
MIT License
11.33k stars 1.07k forks source link

Why is CTkFrame.pack(side = 'top', expand = True, fill = 'both') not filling up the whole screen #2549

Closed Toby1218 closed 1 month ago

Toby1218 commented 1 month ago

I have two files frames, a login page and a navbar. I am trying to pack them into a CTkScrollableFrame which is packed to the CTk root. I don't understand why packing the Login frame to the page with expand = True and fill = 'both' still doesn't fill all the empty space. I have made the background color of the ScrollableFrame red, the result of my code is below.

Screenshot 2024-08-21 114827

In app.py

    class App(ctk.CTkScrollableFrame):
        def __init__(self, root: ctk.CTk):
            super().__init__(root, border_width = 0, corner_radius = 0, fg_color = 'red')
            self.pack(side = 'top', expand = True, fill = 'both')

            self.root = root

            self.login_page = Login(self)

            # init application in scrollable frame
            self.base_app = Navbar(self)
            self.base_app.pack(side = 'top', fill = 'both')

            # pack the page currently in display
            self.login_page.pack(side = 'top', expand = True, fill = 'both')

        def switch_page(self, page):
            for widget in self.pack_slaves():
            widget.pack_forget()

            self.base_app.pack(side = 'top', fill = 'x')

            if page == 'login':
            self.login_page.pack(side = 'top', expand = True, fill = 'both')

            elif page == 'signup':
            self.signup_page.pack(side = 'top', expand = True, fill = 'both')

    root = ctk.CTk()
    root.geometry('1440x810')
    root._set_scaling(1,1)
    root.resizable(False, False)
    app = App(root = root)
    root.mainloop()

In login.py

class Login(ctk.CTkFrame):
    def __init__(self, app: ctk.CTkScrollableFrame):
        super().__init__(app, fg_color = 'white', corner_radius = 0)

        self.method = ['Email', 'Phone Number']
        self.selection = 0

        self.app = app

        self.login_frame = ctk.CTkFrame(self, border_width = 2, corner_radius = 5, border_color = '#e5e5e5', fg_color = 'white')
        self.login_frame.pack(side = 'top', expand = True)

        self.method_frame = ctk.CTkFrame(self.login_frame, border_width = 0, fg_color = 'transparent')
        self.method_frame.pack(side = 'top', expand = True, padx = 50, pady = 20, fill = 'x')

        self.main_label = ctk.CTkLabel(self.method_frame, text = 'Login', font = ('Arial', 25), anchor = 'w')
        self.main_label.pack(side = 'left')

        underline_font = ctk.CTkFont('Arial', 15, underline = True)
        self.method_button = ctk.CTkButton(self.method_frame, text = f'Login with phone number', font = underline_font, fg_color = 'transparent', hover = False, text_color = '#155ca2', anchor = 'w', border_spacing = 0, command = lambda: self.handle_clicks('method'))
        self.method_button.pack(side = 'right')

        self.name_label = ctk.CTkLabel(self.login_frame, text = 'Email', font = ('Arial', 15), anchor = 'w', text_color = '#5a5a5a')
        self.name_label.pack(side = 'top', expand = True, fill = 'x', padx = 50)

        self.name_entry = ctk.CTkEntry(self.login_frame, width = 300, height = 40, fg_color = '#e5e5e5', corner_radius = 20, font = ('Arial', 15))
        self.name_entry.pack(side = 'top', padx = 50, pady = (0,20))

        self.password_label = ctk.CTkLabel(self.login_frame, text = 'Password', font = ('Arial', 15), anchor = 'w', text_color = '#5a5a5a')
        self.password_label.pack(side = 'top', expand = True, fill = 'x', padx = 50)

        self.password_entry = ctk.CTkEntry(self.login_frame, width = 300, height = 40, fg_color = '#e5e5e5', corner_radius = 20, font = ('Arial', 15))
        self.password_entry.pack(side = 'top', padx = 50, pady = (0,30))

        self.login_button = ctk.CTkButton(self.login_frame, text = 'Continue', font = ('Arial', 15), text_color = 'black', fg_color = '#ffd814', hover_color = '#f7ca00', corner_radius = 15, width = 300, height = 30, command = lambda: self.handle_clicks('login'))
        self.login_button.pack(side = 'top', padx = 50, pady = (0,30))

        self.signup_button = ctk.CTkButton(self.login_frame, text = "Don't have an account? Sign Up", font = ('Arial', 15), text_color = 'black', fg_color = '#ffd814', hover_color = '#f7ca00', corner_radius = 15, width = 300, height = 30, command = lambda: self.handle_clicks('signup'))
        self.signup_button.pack(side = 'top', padx = 50, pady = (0,30))

        self.name_entry.bind('<FocusIn>', lambda event: self.handle_focus(event, 'username'))
        self.name_entry.bind('<FocusOut>', lambda event: self.handle_focus(event, 'username'))
        self.password_entry.bind('<FocusIn>', lambda event: self.handle_focus(event, 'password'))
        self.password_entry.bind('<FocusOut>', lambda event: self.handle_focus(event, 'password'))

    def handle_clicks(self, action):
        if action == 'login':
            pass

        elif action == 'method':
            self.selection = 1 - self.selection
            self.method_button.configure(text = f'Login with {self.method[1 - self.selection].lower()}')
            self.name_label.configure(text = self.method[self.selection])
            if self.selection == 1:
                self.name_entry.configure(placeholder_text = 'Country code is not required')

            else:
                self.name_entry.configure(placeholder_text = '')

        elif action == 'signup':
            self.app.switch_page('signup')

    def handle_focus(self, event, widget):
        if int(event.type) == 9:
            if widget == 'username':
                self.name_entry.configure(border_color = '#007185')

            elif widget == 'password':
                self.password_entry.configure(border_color = '#007185')

        elif int(event.type) == 10:
            if widget == 'username':
                self.name_entry.configure(border_color = '#979da2')

            if widget == 'password':
                self.password_entry.configure(border_color = '#979da2')

In navbar.py

class Navbar(ctk.CTkFrame):
    def __init__(self, app: ctk.CTkScrollableFrame):
        super().__init__(app, fg_color = 'white', corner_radius = 0)

        self.app = app

        # create option bar at the top
        self.navbar_frame = ctk.CTkFrame(self, fg_color = '#131921', border_width = -10, corner_radius = 0)
        self.navbar_frame.pack(side = 'top', fill = 'x')

        self.home = ctk.CTkButton(
            self.navbar_frame, text = 'Home', font = ('Arial', 15), command = lambda: self.handle_clicks('home'),
            fg_color = 'transparent', hover_color = '#4a535e', corner_radius = 0
        )
        self.home.pack(side = 'left', fill = 'y', ipadx = 15, ipady = 10)

        self.deals = ctk.CTkButton(
            self.navbar_frame, text = 'Special Deals', font = ('Arial', 15), command = lambda: self.handle_clicks('deals'), 
            fg_color = 'transparent', hover_color = '#4a535e', corner_radius = 0
        )
        self.deals.pack(side = 'left', fill = 'y', ipadx = 15, ipady = 10)

        self.support = ctk.CTkButton(
            self.navbar_frame, text = 'Customer Service', font = ('Arial', 15), command = lambda: self.handle_clicks('customer service'), 
            fg_color = 'transparent', hover_color = '#4a535e', corner_radius = 0
        )
        self.support.pack(side = 'left', fill = 'y', ipadx = 15, ipady = 10)

        # make minigames
        self.points = ctk.CTkButton(
            self.navbar_frame, text = 'Aquire Points', font = ('Arial', 15), command = lambda: self.handle_clicks('points'), 
            fg_color = 'transparent', hover_color = '#4a535e', corner_radius = 0
        )
        self.points.pack(side = 'left', fill = 'y', ipadx = 15, ipady = 10)

        cart_image = ctk.CTkImage(Image.open('assets/cart.png'))
        self.cart = ctk.CTkButton(
            self.navbar_frame, text = 'Cart (0)', image = cart_image, font = ('Arial', 15), command = lambda: self.handle_clicks('cart'), 
            fg_color = 'transparent', hover_color = '#4a535e', corner_radius = 0
        )
        self.cart.pack(side = 'right', fill = 'y', ipadx = 15, ipady = 10)

        self.user_status = ctk.CTkButton(
            self.navbar_frame, text = 'Login / Sign Up', font = ('Arial', 15), command = lambda: self.handle_clicks('account'), 
            fg_color = 'transparent', hover_color = '#4a535e', corner_radius = 0
        )
        self.user_status.pack(side = 'right', fill = 'y', ipadx = 15, ipady = 10)

        # create search bar
        self.searchbar_bg = ctk.CTkFrame(self, fg_color = '#232f3e', border_width = -10, corner_radius = 0)
        self.searchbar_bg.pack(side = 'top', fill = 'x')

        self.searchbar_frame = ctk.CTkFrame(self.searchbar_bg, fg_color = 'transparent', border_width = -10, corner_radius = 0)
        self.searchbar_frame.pack(side = 'top', fill = 'x', padx = 150, pady = 10)

        self.choice = ctk.Variable(self, value = 'All')
        self.category_menu = ctk.CTkOptionMenu(self.searchbar_frame, variable = self.choice, values = ['All', 'teaiudhfiawhd', 'fsiuhefuh'], font = ('Arial', 15), dropdown_font = ('Arial', 15), text_color = 'black', dropdown_text_color = 'black', fg_color = '#d4d4d4', dropdown_fg_color = 'white', button_color = '#d4d4d4', hover = False, dropdown_hover_color = '#d4d4d4', corner_radius = 5, height = 40)
        self.category_menu.pack(side = 'left', fill = 'y')

        self.searchbar = ctk.CTkEntry(self.searchbar_frame, font = ('Arial', 17), fg_color = 'white', border_width = 0, corner_radius = 0)
        self.searchbar.pack(side = 'left', expand = True, fill = 'both')

        search_icon = ctk.CTkImage(Image.open('assets/search_icon.png'))
        self.search_button = ctk.CTkButton(self.searchbar_frame, text = '', image = search_icon, fg_color = '#febd69', hover_color = '#f3a847', border_spacing = 0, corner_radius = 5, width = 40, height = 40)
        self.search_button.pack(side = 'left', fill = 'y')