Closed sunny9495-dev closed 2 years ago
@sunny9495-dev, what is your objective? Are you trying to create one window after destroying another, or to create a brand new window? Or to create two running instances of a window?
ttkbootstrap 1.0+ works a bit differently under the hood than 0.5.
Try something like this:
import ttkbootstrap as ttk
class GuiApp:
def __init__(self):
self.root = ttk.Window(themename='litera', size=(850, 550), resizable=(False, False))
tab_one = ttk.Button(self.root, text='Campaigns')
tab_one.place(x=20, y=20)
tab_two = ttk.Button(self.root, text='Settings')
tab_two.place(x=27, y=60)
def validate(window):
window.destroy()
app = GuiApp()
app.root.mainloop()
def validate_license():
login = ttk.Window(themename='litera', size=(350, 300), resizable=(False,False))
validate_btn = ttk.Button(login, text='Sign-in', command=lambda w=login: validate(w))
validate_btn.place(x=155, y=150)
login.mainloop()
if __name__ == '__main__':
validate_license()
Thanks alot for quick response @israel-dryer,
but, i still having issue mate
self.root = ttk.Window(themename='litera', size=(850, 550), resizable=(False, False))
self.root.layout('TNotebook.Tab', [])
iam using the code to hide the tab headers, but iam getting
AttributeError: '_tkinter.tkapp' object has no attribute 'layout'
Any solution for the issue
Try, self.root.style.layout()
The window class has a style object attached to it.
Here's a reference to the new API https://ttkbootstrap.readthedocs.io/en/latest/gettingstarted/tutorial/
One more issue @israel-dryer,
every style is giving issue.
iam using style='light.TButton'
but iam getting error
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 4929, in __init__
func(self, *args, **kwargs)
File "C:\Python\Lib\tkinter\ttk.py", line 702, in __init__
Entry.__init__(self, master, "ttk::combobox", **kw)
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 4948, in __init__
ttkstyle = Bootstyle.update_ttk_widget_style(
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 5034, in update_ttk_widget_style
builder_method(builder, widget_color)
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 1203, in create_combobox_style
arrowsize=self.scale_size(12),
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 1104, in scale_size
winsys = self.style.master.tk.call("tk", "windowingsystem")
_tkinter.TclError: can't invoke "tk" command: application has been destroyed
bgerror failed to handle background error.
Original error: can't invoke "event" command: application has been destroyed
Error in bgerror: can't invoke "tk" command: application has been destroyed
You are setting a button style?
Try using the argument bootstyle="light"
Sorry to say @israel-dryer, that isnt worked too
File "D:\Python Projects\Activity New\Activity.py", line 128, in __init__
self.browserbtn = ttk.Checkbutton(self.tab2, text="On", bootstyle="success-round-toggle",
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 4943, in __init__
ttkstyle = Bootstyle.update_ttk_widget_style(
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 5034, in update_ttk_widget_style
builder_method(builder, widget_color)
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 3115, in create_round_toggle_style
images = self.create_round_toggle_assets(colorname)
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 3010, in create_round_toggle_assets
size = self.scale_size([24, 15])
File "C:\Python\lib\site-packages\ttkbootstrap\style.py", line 1104, in scale_size
winsys = self.style.master.tk.call("tk", "windowingsystem")
_tkinter.TclError: can't invoke "tk" command: application has been destroyed
bgerror failed to handle background error.
Original error: can't invoke "event" command: application has been destroyed
Error in bgerror: can't invoke "tk" command: application has been destroyed
When are you getting this error? When starting the program, or performing some action?
Can you please post an example of the code in question.
Here is the code @israel-dryer
import ttkbootstrap as ttk
from tkinter import *
class GuiApp:
def __init__(self):
self.root = ttk.Window(themename='litera', size=(850, 550), resizable=(False, False))
self.root.style.configure('lefttab.TNotebook', tabposition='wn')
self.root.style.configure('TNotebook.Tab', align=LEFT)
self.root.style.layout('TNotebook.Tab', [])
self.notebook = ttk.Notebook(self.root, style='lefttab.TNotebook')
self.tab1 = ttk.Frame(self.notebook, width=700, height=500)
self.tab2 = ttk.Frame(self.notebook, width=700, height=500)
self.tab3 = ttk.Frame(self.notebook, width=700, height=500)
self.tab4 = ttk.Frame(self.notebook, width=700, height=500)
self.tab5 = ttk.Frame(self.notebook, width=700, height=500)
self.tab6 = ttk.Frame(self.notebook, width=700, height=500)
self.notebook.add(self.tab1, text="Campaigns")
self.notebook.add(self.tab2, text="Settings")
self.notebook.add(self.tab3, text="Reports")
self.notebook.add(self.tab4, text="Add New Campaign")
self.notebook.add(self.tab5, text="Camp Reports")
self.notebook.add(self.tab6, text="Log Report")
# self.notebook.pack(fill=BOTH, expand=1)
self.notebook.place(x=100, y=20)
tabone = ttk.Button(self.root, text="Campaigns")
tabone.place(x=20, y=20)
tabtwo = ttk.Button(self.root, text="Settings")
tabtwo.place(x=27, y=60)
tabthree = ttk.Button(self.root, text="Reports")
tabthree.place(x=27, y=100)
# Tab1
self.camplbl = ttk.Label(self.tab1, text="Campaigns", bootstyle='info', font='Helvetica 14 bold')
self.camplbl.place(x=10, y=20)
self.addcamp = ttk.Button(self.tab1, text="Add New Campaign", bootstyle='primary')
self.addcamp.place(x=10, y=60)
self.label = ttk.Label(self.tab1, text="Search", bootstyle='info', font=(('Arial'), 11))
self.label.place(x=10, y=110)
self.searchentry = ttk.Entry(self.tab1, width=30)
self.searchentry.place(x=65, y=105)
def run_camp(self):
pass
def validate(window):
window.destroy()
app = GuiApp()
app.root.mainloop()
def validate_license():
login = ttk.Window(themename='litera', size=(350, 300), resizable=(False,False))
validate_btn = ttk.Button(login, text='Sign-in', command=lambda w=login: validate(w))
validate_btn.place(x=155, y=150)
login.mainloop()
if __name__ == '__main__':
validate_license()
One more thing is the tabs headers isnt hiding and the second window doesnt appear in bootstrap style
I need to look into this further, but generally, it is not a recommended practice to use more than one tcl/tk interpreter in your application. This is what Toplevel
widgets are created for. There are several ways to accomplish what you want without closing and reopening a new application window.
On solution, as I mentioned, is to use Toplevel
widgets.
Another solution (demonstrated below) is to use frames to control and contain your content.
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
THEME = 'litera'
APP_SIZE = (850, 550)
class GuiApp(ttk.Window):
def __init__(self):
super().__init__(themename=THEME, size=APP_SIZE, resizable=(False, False))
self.is_valid_license = ttk.BooleanVar(self, name='is_valid_license', value=False)
self.is_valid_license.trace_add('write', self.on_license_validation)
# setup frames
self.setup_custom_styles()
self.validation_frame = LicenseValidationFrame(self)
self.main_frame = MainAppFrame(self)
# show the initial validation frame
self.show_validation_frame()
def show_main_frame(self):
self.main_frame.pack(fill=BOTH, expand=YES)
def show_validation_frame(self):
if not self.validation_frame.winfo_ismapped():
self.validation_frame.pack(fill=BOTH, expand=YES)
def setup_custom_styles(self):
self.style.configure('lefttab.TNotebook', tabposition='wn')
self.style.configure('TNotebook.Tab', align=LEFT, fill=X)
self.style.layout('TNotebook.Tab', [])
def on_license_validation(self, *args):
if self.is_valid_license.get():
self.validation_frame.pack_forget()
self.show_main_frame()
class MainAppFrame(ttk.Frame):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
# setup buttons
self.lframe = ttk.Frame(self, padding=(10, 10, 0, 10))
self.lframe.pack(side=LEFT, fill=Y)
self.tab1_btn = ttk.Button(self.lframe, text='Campaigns')
self.tab2_btn = ttk.Button(self.lframe, text='Settings')
self.tab3_btn = ttk.Button(self.lframe, text='Reports')
self.tab1_btn.pack(side=TOP, fill=X)
self.tab2_btn.pack(side=TOP, fill=X)
self.tab3_btn.pack(side=TOP, fill=X)
# setup notebook & tabs
self.rframe = ttk.Frame(self)
self.rframe.pack(side=RIGHT, fill=BOTH)
self.notebook = ttk.Notebook(self.rframe, style='lefttab.TNotebook')
self.notebook.pack(fill=BOTH, expand=YES, padx=10, pady=10)
tab_cnf = {'width': 700, 'height': 500}
# tab 1 setup
self.tab1 = CampaignTab(self.notebook)
self.tab2 = ttk.Frame(self.notebook, **tab_cnf)
self.tab3 = ttk.Frame(self.notebook, **tab_cnf)
self.tab4 = ttk.Frame(self.notebook, **tab_cnf)
self.tab5 = ttk.Frame(self.notebook, **tab_cnf)
self.tab6 = ttk.Frame(self.notebook, **tab_cnf)
self.notebook.add(self.tab1, text='Campaigns')
self.notebook.add(self.tab2, text='Settings')
self.notebook.add(self.tab3, text='Reports')
self.notebook.add(self.tab4, text='Add New Campaign')
self.notebook.add(self.tab5, text='Camp Reports')
self.notebook.add(self.tab6, text='Log Reports')
class CampaignTab(ttk.Frame):
def __init__(self, master, **kwargs):
super().__init__(master, width=700, height=500, **kwargs)
# create tab elements
self.camp_lbl = ttk.Label(self, text='Campaigns', bootstyle=INFO, font='Helvetica 14 bold')
self.add_camp = ttk.Button(self, text='Add New Campaign', bootstyle=PRIMARY)
self.search_lbl = ttk.Label(self, text='Search', bootstyle=INFO, font='Arial 11')
self.search_entry = ttk.Entry(self)
# set layout
self.camp_lbl.pack(pady=10)
self.add_camp.pack(pady=10)
self.search_entry.pack(pady=10)
class LicenseValidationFrame(ttk.Frame):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
btn = ttk.Button(self, text='Sign-in', command=self.validate)
btn.place(anchor=CENTER, relx=0.5, rely=0.5)
def validate(self):
"""perform some function to validate the license then update
the is_valid_license variable"""
is_valid_license = ttk.BooleanVar(name='is_valid_license')
is_valid_license.set(True)
if __name__ == '__main__':
app = GuiApp()
app.mainloop()
In fact, since you are creating your own notebook buttons, you really do not need to use the notebook widget at all, just use the pack_forget
method to remove the frame from the window as I did for the license frame above, and then pack the tab you want to show. The result will be the same except you won't need to do a lot of customizations on the notebook widget.
One other tip, I would avoid using place with x & y coordinates. If someone has a high resolution screen, the placement of widgets will be very different than you expect. If you need to use the place
geometry manager, prefer to use relx or rely to make relative position placements.
here's with just the tabs
Ok, Thanks @israel-dryer
Thank you for your excellent support
I just want to add a note on how to solve the application has been destroyed
error.
My script is a module and the end user might use it ether with tk or pyside or what ever so I needed the functionality to create new tk instances.
The solution was to set Style.instance = None
before setting the theme. That way the Style command will create a new instance.
This is how my code looks like:
window = tk.Tk()
Style.instance = None
Style(theme="superhero")
@israel-dryer Maybe there could be an argument for Style() to create a new instance even if an old one exist for these cases?
Desktop (please complete the following information):
Hi,
I use the following code to spawn the next UI, but iam getting error
_tkinter.TclError: NULL main window
If i tried with same code with ttkboostrap version 0.5.1 then no issue.
Describe the bug
Getting _tkinter.TclError: NULL main window bug when it was trying to spawn other UI
To Reproduce
Just run the code and click on sign in button, you can see the bug
Expected behavior
It has to spawn the other UI, it works fine V0.5.1, but not in the current.
Screenshots
https://i.imgur.com/8zaETCY.png
Additional context
No response