Search code examples
pythonuser-interfacetkinterttkbootstrap

How to create a new window over another window with ttkbootstrap?


I created a Login window and label on which you can click and open Signup window, but both implemented as separate classes using ttk.Window(), so when it opens Signup window over Login window it fully distorts the appearance of SignUp window, how can I fix it?

I tried to implement SignUp using TopLevel but it looks completely different than simple ttk.Window, so I don't want it. Is there other method to implement that in ttkbootstrap? Maybe there are some other external libraries which allow to create an appealing modern gui?

(sorry for my poor English)

Here is my gui code (but without commands, events, etc.)

login.py:

class LogIn:
    def __init__(self):
        self.root = ttk.Window(themename='morph')
        self.root.title("Log in")
        self.root.geometry('450x550')
        self.root.minsize(450, 400)

        self.label = ttk.Label(self.root, text='Welcome back!', font=('Ebrima', 16), bootstyle='info')  
        self.label.place(relx=0.253, rely=0.15)

        # email entry
        self.email_entry = ttk.Entry(self.root, width=25, font=('Ebrima', 10), foreground='gray')
        self.email_entry.insert(0, 'Enter your email')
        self.email_entry.place(relx=0.185, rely=0.32)

        # password entry
        self.password_entry = ttk.Entry(self.root, width=25, font=('Ebrima', 10), foreground='gray')
        self.password_entry.insert(0, 'Enter your password')
        self.password_entry.place(relx=0.185, rely=0.43)

        # checkbutton
        self.check_var = BooleanVar(value=True)
        self.check_button = ttk.Checkbutton(self.root, text='Show password', variable=self.check_var, bootstyle='info')
        self.check_button.place(relx=0.5, rely=0.54)

        # login button
        self.login_button = ttk.Button(self.root, text='Log in', bootstyle='info', width=14)
        self.login_button.place(relx=0.315, rely=0.73, anchor='w')
        
        self.label_under = ttk.Label(self.root, text='Don\'t have an account?', font=('Ebrima', 9))
        self.label_under.place(relx=0.165, rely=0.775)

        self.label_signup = ttk.Label(self.root, text='Sign up now', font=('Ebrima', 9), bootstyle='primary',
                                      cursor='hand2')
        self.label_signup.place(relx=0.59, rely=0.775)
        self.label_signup.bind('<Button-1>', lambda event: self._open_signup_window())

    def _open_signup_window(self):
        c = SignUp()
        c.root.mainloop()

signup.py :

class SignUp:  
    def __init__(self):
        self.root = ttk.Window(themename='morph')
        self.root.title('Sign up')
        self.root.geometry('450x600')
        self.root.minsize(450, 650)

        # Main label
        self.label = ttk.Label(self.root, text='Create an account', font=('Ebrima', 17), bootstyle='info')
        self.label.place(relx=0.195, rely=0.13)

        # Name entry
        self.name_entry = ttk.Entry(self.root, width=25, font=('Ebrima', 10), foreground='gray')
        self.name_entry.insert(0, 'Enter your name')
        self.name_entry.place(relx=0.18, rely=0.28)

        # Email entry
        self.email_entry = ttk.Entry(self.root, width=25, font=('Ebrima', 10), foreground='gray')
        self.email_entry.insert(0, 'Enter your email')
        self.email_entry.place(relx=0.18, rely=0.38)

        # Password entry
        self.password_entry = ttk.Entry(self.root, width=25, font=('Ebrima', 10), foreground='gray')
        self.password_entry.insert(0, 'Enter your password')
        self.password_entry.place(relx=0.18, rely=0.48)

        # Password confirmation entry
        self.confirm_password_entry = ttk.Entry(self.root, width=25, font=('Ebrima', 10), foreground='gray')
        self.confirm_password_entry.insert(0, 'Confirm your password')
        self.confirm_password_entry.place(relx=0.18, rely=0.58)

        # Show password checkbutton
        self.check_var = BooleanVar(value=True)
        self.show_password_check = ttk.Checkbutton(self.root, text='Show password', variable=self.check_var,
                                                   bootstyle='info')
        self.show_password_check.place(relx=0.5, rely=0.67)

        # Sign up button
        self.signup_button = ttk.Button(self.root, text='Sign up', bootstyle='info', width=15)
        self.signup_button.place(relx=0.3, rely=0.825, anchor='w')

So when I run this code, the LogIn window looks perfect as I want it to look like, but when I click label_signup, SignUp window appears but all its labels, buttons, entries look like they have no background (more precisely, the background of each widget looks like white rectangle, but window background color is blue (due to theme I used) and some logic of my program doesn't work properly. In addition to this, I would like to close the LogIn window when label_signup is clicked, to be able to use SignUp window properly. So the main question I ask is why I can't display two ttkbootstrap windows concurrently so that neither of them is distorted. If not, maybe you could recommend some other modern gui libraries/frameworks which allow doing such stuff. I would appreciate any advice you give!


Solution

  • My guess is that this is a bug in ttkbootstrap that is triggered when you create more than one Window. In general, tkinter isn't designed to have more than one root window. You can do it, but the behavior is not going to be obvious.

    Instead, any windows other than the root window need to be a Toplevel window. For example:

    class SignUp:
        def __init__(self):
            self.root = ttk.Toplevel()
            ...
    

    Also, you do not need to call mainloop more than once. You shouldn't call it for each window.