I'm creating software using tkinter and ttkbootstrap and on that software, users have to log in first. If they log in they will redirect to the Home window. But when a user logged in and redirected to the Home window the style of the Home window not working. Specifically, the bootstyle is not working. But the style of the Home window works when I run it only. This means if I run the home.py the style works perfectly. But, if I show the home window after destroying the login window it's not working.
My main.py code:
import ttkbootstrap as ttk
from orm.window.loginwindow import LoginWindow
from orm.home.home import Home
from database.internet import have_internet
from ttkbootstrap.dialogs import Messagebox
if __name__ == "__main__":
app = LoginWindow()
# app = Home()
print(app)
app.mainloop()
My log in window code:
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox
from database.auth import login
from orm.home.home import Home
from database.internet import have_internet
import sys, os
sys.path.insert(0, os.path.abspath('..'))
class LoginWindow(ttk.Window):
def __init__(self):
super().__init__(themename="superhero")
self.title("MidGen (Login)")
self.geometry("750x550")
# username entry
ttk.Label(self, text="Username: ").place(relx=0.3, rely=0.3)
self.username = ttk.Entry(self)
self.username.configure(bootstyle="success", width=40)
self.username.place(relx=0.3, rely=0.35)
# password entry
ttk.Label(self, text="Password: ").place(relx=0.3, rely=0.45)
self.password = ttk.Entry(self)
self.password.configure(bootstyle="success", width=40, show="*")
self.password.place(relx=0.3, rely=0.50)
# show pass or not
self.show_or_not = ttk.IntVar()
pass_check = ttk.Checkbutton(
self, bootstyle="primary",
text="Show password",
variable=self.show_or_not,
onvalue=1,
offvalue=0,
command=lambda: self.password.configure(show="") if self.show_or_not.get() == 1 else self.password.configure(show="*"))
pass_check.place(relx=0.3, rely=0.60)
# login button
login_btn = ttk.Button(self)
login_btn.configure(bootstyle="success", text="Login", width=40, command=self.login)
login_btn.place(relx=0.3, rely=0.67)
self.resizable(False, False)
def login(self):
un = self.username.get()
ps = self.password.get()
if not have_internet():
Messagebox.show_error("Check your internet connection", "Error")
return
data = login(un, ps)
print(data["status"])
if data["status"] == 200:
self.destroy()
home_view = Home()
style = ttk.Style("darkly")
home_view.mainloop()
else:
Messagebox.show_error("Username not found or wrong password\nTry again!", "Error")
My home window code:
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
import tkinter as tk
from ..common.menubar import Menubar
from ..frames.frames import Dashboard, Map
class Home(ttk.Window):
def __init__(self):
super().__init__(themename="superhero")
self.title("MidGen")
self.width = self.winfo_screenwidth()
self.height = self.winfo_screenheight()
self.geometry(f"{self.width}x{self.height}")
menubar = Menubar(self)
self.config(menu=menubar.menubar)
# sidebar
self.sidebar = ttk.Frame(self, bootstyle="success")
self.sidebar.configure(bootstyle="success")
self.sidebar.place(relx=0, rely=0, relwidth=0.2, relheight=1)
self.brand_frame = ttk.Frame(self.sidebar, bootstyle="success")
self.brand_frame.place(relx=0, rely=0, relwidth=1, relheight=0.15)
bname = ttk.Label(self.brand_frame,
text="MidGen",
bootstyle="inverse-success",
font=("", 15, "bold"))
bname.place(relx=.5, rely=.1, anchor="center")
# sidebar button frame
self.options = ttk.Frame(self.sidebar, bootstyle="success")
self.options.place(relx=0, rely=0.05, relwidth=1, relheight=.2)
# home button
self.op1 = ttk.Button(self.options,
text="Dashboard",
style="TButton",
command=self.show_dashboard)
self.op1.place(relx=0, rely=0, relwidth=1)
self.op1['padding'] = (10, 10)
# cursor pointer on hover
self.op1.bind("<Enter>", self.on_button_enter)
self.op1.bind("<Leave>", self.on_button_leave)
# contacts button
self.op2 = ttk.Button(self.options,
text="Contacts",
command=self.show_contacts)
self.op2.place(relx=0, rely=.4, relwidth=1)
self.op2['padding'] = (10, 10)
self.op2.bind("<Enter>", lambda event: self.op2.config(cursor="hand2"))
self.op2.bind("<Leave>", lambda event: self.op2.config(cursor=""))
# map button
self.op3 = ttk.Button(self.options,
text="Map",
command=lambda: self.map.tkraise())
self.op3.place(relx=0, rely=.8, relwidth=1)
self.op3['padding'] = (10, 10)
self.op3.bind("<Enter>", lambda event: self.op3.config(cursor="hand2"))
self.op3.bind("<Leave>", lambda event: self.op3.config(cursor=""))
# dashboard
self.dashboard = ttk.Frame(self, bootstyle="danger")
self.dashboard.place(relx=.2, rely=0, relwidth=.8, relheight=1)
self.maindash = Dashboard(self.dashboard)
self.maindash.place(relx=0, rely=0)
# contacts
self.contacts = ttk.Frame(self, bootstyle="warning")
self.contacts.place(relx=.2, rely=0, relwidth=.8, relheight=1)
# map
self.map = ttk.Frame(self, bootstyle="dark")
self.map.place(relx=.2, rely=0, relwidth=.8, relheight=1)
self.mainmap = Map(self.map)
self.mainmap.place(relx=0, rely=0, relwidth=1, relheight=1)
self.dashboard.tkraise()
def show_dashboard(self):
self.dashboard.tkraise()
def show_contacts(self):
self.contacts.tkraise()
def on_button_enter(self, event):
self.op1.config(cursor="hand2") # Change cursor to pointer on hover
def on_button_leave(self, event):
self.op1.config(cursor="")
I tried to apply the theme many ways but none of them worked.
Since
ttkbootstrap.Style
class uses single instance logic, so it uses a class variableinstance
to store the reference of the first created instance.ttkbootstrap.Style
When
LoginWindow
is destroyed, the instance ofStyle
created insideLoginWindow
is also destroyed but the class variableStyle.instance
still refers to the destroyed instance. So subsequent functions called on the style will raise exception.You need to reset the class variable
instance
toNone
after destroyingLoginWindow
: