I'm trying to have a ttk notebook display 2 tabs based on 2 classes, the code is the following :
import tkinter as tk
from tkinter import ttk
class Dashboard:
def __init__(self,master):
self.master = master
self.frame = tk.Frame(self.master, width = 400, height = 400, bg = "red")
self.frame.pack(expand = True)
class Options :
def __init__(self,master):
self.master = master
self.frame = tk.Frame(self.master, width = 400, height = 400, bg = "blue")
self.frame.pack(expand = True)
class Tabs:
def __init__(self,master):
self.master = master
self.notebook = ttk.Notebook(self.master)
self.options = Options(self.notebook)
self.dashboard = Dashboard(self.notebook)
self.notebook.add(self.options)
self.notebook.add(self.dashboard)
self.notebook.pack(pady=10, expand=True)
class MainGUI:
def __init__(self,master):
self.master = master
self.tabs = Tabs(self.master)
if __name__ == '__main__':
root = tk.Tk()
gui = MainGUI(root)
root.mainloop()
However, when I run this I have this error (only happens when I try to use the "add" method of the ttk.Notebook) :_tkinter.TclError: bad window path name "<__main__.Options object at 0x0000016E51653DC0>"
I don't understand why my syntax is wrong, can someone help me with that ?
Thanks a lot !!
A child pane widget is usually a Frame or a subclass of one. I'm not exactly sure what you're doing, but you can get rid of the error (and a similar one for the other class) by deriving both of them from the tkinter Frame class like this:
import tkinter as tk
from tkinter import ttk
class Dashboard(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.frame = tk.Frame(self.master, width=400, height=400, bg="red")
self.frame.pack(expand=True)
class Options(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.frame = tk.Frame(self.master, width=400, height=400, bg="blue")
self.frame.pack(expand=True)
class Tabs:
def __init__(self,master):
self.master = master
self.notebook = ttk.Notebook(self.master)
self.options = Options(self.notebook)
self.dashboard = Dashboard(self.notebook)
self.notebook.add(self.options)
self.notebook.add(self.dashboard)
self.notebook.pack(pady=10, expand=True)
class MainGUI:
def __init__(self,master):
self.master = master
self.tabs = Tabs(self.master)
if __name__ == '__main__':
root = tk.Tk()
gui = MainGUI(root)
root.mainloop()
Related
I have a script, and woult like to have some imputs, outputs (as in the terminal) and a start running script.
How can I do this?
this is what I have for now:
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
exitButton = Button(self, text="Run", command=self.clickExitButton)
exitButton.place(x=0, y=0)
def clickrunButton(self):
run() #this doesnt work
root = Tk()
app = Window(root)
# set window title
root.wm_title("Tkinter window")
# show window
root.mainloop()
You have to place your app in the root, for example with pack(). You also have to change the name of the function, because it doesn't match the one you give to the button command.
from tkinter import *
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.pack() # Window is packed in its master.
exitButton = Button(self, text="Run", command=self.clickrunButton)
exitButton.pack()
def clickrunButton(self):
self.run() # Now this work
def run(self):
print('Something')
root = Tk()
app = Window(root)
# set window title
root.wm_title("Tkinter window")
# show window
root.mainloop()
When attempting to create a second Toplevel in Tkinter after closing the first I get the error:
_tkinter.TclError: bad window path name ".!toplevel
The error only occurs when the first Toplevel is closed, when I run the code without close_window() no error occurs and new_window works and creates the second Toplevel. I need to be able to close the first Toplevel and am not sure what is going wrong here so any help is much appreciated.
Here is a minimal reproducible example.
import tkinter as tk
class auto_haven:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.frame.place(relwidth=1, relheight=1)
self.admin_login_button = tk.Button(self.frame, text="Admin Login", font=40, command=self.new_window)
self.admin_login_button.place(relwidth=1, relheight=1)
def new_window(self):
self.newWindow = tk.Toplevel(self.master)
self.app = admin_login(self.newWindow)
class admin_login:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.frame.place(relwidth=1, relheight=1)
self.login_button = tk.Button(self.frame, text="Login", font=40, command=self.login)
self.login_button.pack()
self.back_button = tk.Button(self.frame, text="Exit", font=40, command=self.close_window)
self.back_button.pack()
def new_window(self):
self.newWindow = tk.Toplevel(self.master)
self.app = admin_panel(self.newWindow)
def close_window(self):
self.master.destroy()
def login(self):
self.close_window()
self.new_window()
class admin_panel:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_window)
self.quitButton.pack()
self.frame.pack()
def close_window(self):
self.master.destroy()
def main():
root = tk.Tk()
app = auto_haven(root)
root.mainloop()
if __name__ == '__main__':
main()
When you call self.login, the first thing it does is call self.close_window(). When you do that, it calls self.master.destroy(). It then calls self.new_window() which calls self.newWindow = tk.Toplevel(self.master).
Notice that you are now trying to create a new window as a child of self.master, but you've destroyed self.master so tkinter will throw an error. When you create a new window, it needs to be the child of an existing window, such as the root window.
Communication between objects
The idea is create a Toplevel window from Gui and after Toplevel closed send the data (name) from Toplevel Entry back to Gui
How object app can know whether the toplev object was destroyed?
or with other words
How can object of Gui know that the object of My_Toplevel is closed?
from tkinter import *
font1 = font=("Open Sans Standard",16,"bold")
class My_Toplevel():
def __init__(self, master=None):
self.master = master
self.toplev = Toplevel(master)
self.name = None
self.create_widgets()
def create_widgets(self):
self.entry_name = Entry(self.toplev, font=font1)
self.button_ok = Button(self.toplev, text="Ok", font=font1,
command=self.get_name)
self.entry_name.pack()
self.button_ok.pack()
def get_name(self):
self.name = self.entry_name.get()
self.toplev.destroy()
class Gui(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.pack()
self.master = master
self.label_text = Label(self, text="Foo Bar Window", font=font1)
self.label_text.pack()
self.button_toplevel = Button(self, text="Create Toplevel",
command=self.get_toplevel, font=font1)
self.button_toplevel.pack()
def get_toplevel(self):
self.my_top = My_Toplevel(self)
if __name__ == "__main__":
root = Tk()
root.title("Parent")
app = Gui(root)
root.mainloop()
You need to pass the data to the Gui instance before you destroy My_Toplevel. One way to do that is to save the name string as an attribute of the Gui instance since you pass that the master parameter when you call My_Toplevel. For example:
from tkinter import *
font1 = font=("Open Sans Standard",16,"bold")
class My_Toplevel():
def __init__(self, master=None):
self.master = master
self.toplev = Toplevel(master)
self.create_widgets()
def create_widgets(self):
self.entry_name = Entry(self.toplev, font=font1)
self.button_ok = Button(self.toplev, text="Ok", font=font1,
command=self.get_name)
self.entry_name.pack()
self.button_ok.pack()
def get_name(self):
self.master.name_data = self.entry_name.get()
self.toplev.destroy()
class Gui(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.pack()
self.master = master
self.label_text = Label(self, text="Foo Bar Window", font=font1)
self.label_text.pack()
self.button_toplevel = Button(self, text="Create Toplevel",
command=self.get_toplevel, font=font1)
self.button_toplevel.pack()
self.name_data = None
Button(self, text="show name", command=self.show_name).pack()
def show_name(self):
print("Name =", self.name_data)
def get_toplevel(self):
self.my_top = My_Toplevel(self)
if __name__ == "__main__":
root = Tk()
root.title("Parent")
app = Gui(root)
root.mainloop()
Press the "show name" button to print the name string to the console.
If you need to save more than a single string, you could append the name to a list, save it in a dictionary, etc.
If you like, you can call the Gui.show_name method just before the TopLevel window is destroyed:
def get_name(self):
self.master.name_data = self.entry_name.get()
self.master.show_name()
self.toplev.destroy()
I have a problem that my top window is not minimize able when i use a grab_set() on the main window.
Here is a code example:
import Tkinter as tk
class mainApView(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
self.master = master
self.master.title("Mainwindow")
self.master.geometry("300x100")
self.frame = tk.Frame(self.master)
self.button = tk.Button(self.frame,text="create top level", command=self.createTopLevel)
self.button.pack()
self.frame.pack()
def createTopLevel(self):
popupWindow = tk.Toplevel(self.master)
# this function disables the minimize button
self.master.grab_set()
newTopLevel(popupWindow)
class newTopLevel():
def __init__(self,master):
self.master = master
self.master.title("New Top Level Window")
self.master.geometry("300x100")
self.frame = tk.Frame(self.master)
self.button = tk.Button(self.frame, text="useless button")
self.button.pack()
self.frame.pack()
def main():
root = tk.Tk()
app = mainApView(root)
root.mainloop()
if __name__ == '__main__':
main()
Is there a workaround? Or are the similar functions like grab_set?
Or how can i override the minimize button?
EDIT My goal is that the minimize button from the top window works and the mainwindow is disabled
I need help with tkinter frames handling and calling objects into it. Here's my example :
from tkinter import *
class Main(Tk):
def __init__(self):
Tk.__init__(self)
self.frame_one = Frame(self)
self.frame_two = Frame(self)
self.frame_one.pack()
self.frame_two.pack()
self.someclassobj = SomeClass(self.frame_one)
self.someclassobj.pack()
class SomeClass(Frame):
def __init__(self, master):
Frame.__init__(self)
self.frame = Frame(master)
self.frame.pack()
self.btn = Button(self.frame, text='click', command=self.btn_func)
self.btn.pack()
def btn_func(self):
Main.someclassobjtwo = SomeClassTwo(Main.frame_two)
Main.someclassobjtwo.pack()
class SomeClassTwo(Frame):
def __init__(self, master):
Frame.__init__(self)
self.frame = Frame(master)
self.msg = Label(self.frame, text='some msg')
self.msg.pack()
app = Main()
app.mainloop()
I need to call object of SomeClassTwo at Main.frame_two , but i get AttributeError: type object 'Main' has no attribute 'frame_two'
I really don't know why that happens.