calling objects at tkinter frame - python

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.

Related

notebook.add() returns bad window path name

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()

how to pack tkiner object in other class?

class SettingsFrame(tk.Frame):
"""docstring for SettingsFrame"""
def __init__(self, master):
self.master = master
self = tk.Frame(self.master)
self.url_label = tk.Label(self, text="Product URL")
self.url_label.pack(side="left")
self.url_entry = tk.Entry(self)
self.url_entry.pack(side="left")
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.settings_frame = SettingsFrame(self)
self.settings_frame.pack(side="top")
def main():
root = tk.Tk()
app = Application(master=root)
app.mainloop()
if __name__ == "__main__":
main()
I'm tryining to structure my code as suggested in this answer - https://stackoverflow.com/a/17470842/12355344, but I'm not sure how to correctly pack() this SettingsFrame with label and entry into Application class.
AttributeError: 'SettingsFrame' object has no attribute 'tk'
Please try this way:
import tkinter as tk
class SettingsFrame(tk.Frame):
"""docstring for SettingsFrame"""
def __init__(self, master=None):
super().__init__(master)
self.url_label = tk.Label(self, text="Product URL")
self.url_label.pack(side="left")
self.url_entry = tk.Entry(self)
self.url_entry.pack(side="left")
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.settings_frame = SettingsFrame()
self.settings_frame.pack(side="top")
def main():
root = tk.Tk()
app = Application(master=root)
app.mainloop()
if __name__ == "__main__":
main()
I've removed the following lines:
self.master = master
self = tk.Frame(self.master)
and added(for SettingsFrame):
super().__init__(master)

Tkinter destroying Toplevel and creating another error

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.

Increasing the ProgressBar in tkinter by x amount entered

I'm having problem with a function that I'm working on. The goal i'm trying to achieve is that, when a number is:
I have a Progress Bar, with the max limit being 1462.
Whenever a number is entered into the window, and the Submit button is pressed, I just simply want the Progress Bar to increase by how much was entered into the window.
I'm getting an error on my increase_progress function, and not being able to achieve the desired result.
Relevant code:
class Window(Frame):
def __init__(self, master):
super().__init__(master)
master.title('Learning Python')
master.configure(background='black')
master.geometry('900x200')
master.resizable(0, 0)
class Submit(Button):
def __init__(self, master):
super().__init__(master)
self.configure(text='Submit', background='black', foreground='light green', highlightthickness=0,
border=0)
class Clear(Button):
def __init__(self, master):
super().__init__(master)
self.configure(text='Clear', background='black', foreground='light green', highlightthickness=0,
border=0)
class ProgressBar(ttk.Progressbar):
def __init__(self, master):
super().__init__(master)
self.config(orient='horizontal', maximum=1462, mode='determinate')
class PagesRead(Label):
def __init__(self, master):
super().__init__(master)
self.config(text='How many page(s) did you read?', background='black', foreground='light green')
class EntryBox(Entry):
def __init__(self, master):
super().__init__(master)
def increase_progress():
progress = int(entry.get())
if progress:
ProgressBar.step(progress)
root = tk.Tk()
app = Window(root)
bar = ProgressBar(root)
bar.pack(fill=tk.BOTH)
pages = PagesRead(root)
pages.pack()
entry = EntryBox(root)
entry.pack()
submit = Submit(root)
submit.pack()
clear = Clear(root)
clear.config(command=lambda: entry.delete(0, 'end'))
clear.pack()
app.mainloop()
import tkinter as tk
import tkinter.ttk as ttk
class Window(tk.Frame):
def __init__(self, master):
super().__init__(master)
master.title('Learning Python')
master.configure(background='black')
master.geometry('900x200')
master.resizable(0, 0)
class Submit(tk.Button):
def __init__(self, master):
super().__init__(master)
self.configure(text='Submit', background='black', foreground='light green', highlightthickness=0,
border=0, command=increase_progress)
class Clear(tk.Button):
def __init__(self, master):
super().__init__(master)
self.configure(text='Clear', background='black', foreground='light green', highlightthickness=0,
border=0)
class ProgressBar(ttk.Progressbar):
def __init__(self, master):
super().__init__(master)
self.config(orient='horizontal', maximum=1462, mode='determinate')
class PagesRead(tk.Label):
def __init__(self, master):
super().__init__(master)
self.config(text='How many page(s) did you read?', background='black', foreground='light green')
class EntryBox(tk.Entry):
def __init__(self, master):
super().__init__(master)
def increase_progress():
progress = int(entry.get())
if progress:
bar['value'] += progress
root = tk.Tk()
app = Window(root)
bar = ProgressBar(root)
bar.pack(fill=tk.BOTH)
pages = PagesRead(root)
pages.pack()
entry = EntryBox(root)
entry.pack()
submit = Submit(root)
submit.pack()
clear = Clear(root)
clear.config(command=lambda: entry.delete(0, 'end'))
clear.pack()
app.mainloop()
Your problem was that you haven't used the value method in progressbar. This code works :) check it out

Communication between python objects?

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()

Categories

Resources