Communication between python objects? - python

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

Related

How can I make a tkinter Toplevel window dependent on another Toplevel window

If I create a Toplevel popup window in a tkinter application, when I close the main root window all sub windows are closed.
With the following code, if I open up two successive Toplevel windows, I can close "Window One" but "Window Two" stays open.
#!/usr/bin/env python3
import tkinter as tk
import tkinter.ttk as ttk
def main():
root = tk.Tk()
root.geometry("600x300")
root.title("Main Window")
app = Application(root)
app.mainloop()
def window_one():
window_one = WindowOne()
window_one.geometry("450x200")
window_one.title('Window One')
def window_two():
window_two = WindowTwo()
window_two.geometry("200x100")
window_two.title('Window Two')
class Application(ttk.Frame):
def __init__(self, master= None, *args, **kwargs):
super().__init__(master = master)
self.pack()
self.create_widgets()
def create_widgets(self):
button1 = ttk.Button(self, text = "Click Here", command = window_one)
button1.pack()
class WindowOne(tk.Toplevel):
def __init__(self, master= None, *args, **kwargs):
super().__init__(master = master)
self.create_widgets()
def create_widgets(self):
button1 = ttk.Button(self, text = "Click Here", command = window_two)
button1.pack()
class WindowTwo(tk.Toplevel):
def __init__(self, master= None, *args, **kwargs):
super().__init__(master = master)
self.create_widgets()
def create_widgets(self):
button1 = ttk.Button(self, text = "$$$")
button1.pack()
if __name__ == "__main__":
main()
How can I code this to make Window Two dependent on Window One so that if I close "Window One", "Window Two" also closes, mimicking the behaviour of the main root window?
You can make Window One the parent of Window Two:
def window_two(parent):
window_two = WindowTwo(parent) # pass parent to WindowTwo
window_two.geometry("200x100")
window_two.title('Window Two')
...
class WindowOne(tk.Toplevel):
def __init__(self, master= None, *args, **kwargs):
super().__init__(master = master)
self.create_widgets()
def create_widgets(self):
button1 = ttk.Button(self, text = "Click Here", command = lambda: window_two(self)) # pass self to `window_two()`
button1.pack()
Update: if you want to close Window One when Window Two is closed, you can use self.protocol("WM_DELETE_WINDOW", ...):
class WindowTwo(tk.Toplevel):
def __init__(self, master= None, *args, **kwargs):
super().__init__(master = master)
self.create_widgets()
self.protocol("WM_DELETE_WINDOW", self.on_destroy)
def create_widgets(self):
button1 = ttk.Button(self, text = "$$$")
button1.pack()
def on_destroy(self):
self.master.destroy() # close parent window
self.destroy() # close itself
or bind <Destroy> event to a callback to close the parent window:
class WindowTwo(tk.Toplevel):
def __init__(self, master= None, *args, **kwargs):
super().__init__(master = master)
self.create_widgets()
self.bind("<Destroy>", self.on_destroy)
def create_widgets(self):
button1 = ttk.Button(self, text = "$$$")
button1.pack()
def on_destroy(self, event):
self.master.destroy() # close parent window

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.

Editing GUI from another GUI after run-time in Tkinter

I have two classes with produce two separate GUI windows. I am struggling to implement a situation where e.g. if a button is pressed in the first GUI, it adds a label to the second GUI after run-time. Could someone please provide me with a solution to this?
Class CustomerOrder:
def __init__(self, master):
self.master = master
master.title("Customer Order GUI")
self.completedButton1 = Label(master,text=" Place Order:")
self.completedButton1.pack(side=TOP)
root = Tk()
my_gui = CustomerOrder(root)
root.mainloop()
class baristaPage(tk.Frame):
def __init__(self, master):
self.master = master
master.title("baristaPage")
self.baristaPage = Label(text="Barista Page")
self.baristaPage.place(x=0,y=0)
dashboard = Label(text="Customer Queue System")
dashboard.place(x=0,y=80)
root = Tk()
my_gui = baristaPage(root)
root.mainloop()
Here is a sample code that creates the Barista and the Customer windows. The Customer window contain a Button, and each time you press this button, it increments the order counter and updates the Barista window. Is this the kind of stuff that you need?
from tkinter import *
class Customer(Toplevel):
def __init__(self, master):
Toplevel.__init__(self) # create the secondary window
self.title("Customer")
self.master = master
self.counter = 0
self.customer = Label(self, text="Customer Page", width=40)
self.customer.pack(side=TOP)
self.button = Button(self, text="Place Order:", command=self.order)
self.button.pack(side=TOP)
self.mainloop()
def order(self):
self.counter += 1
self.master.dashboard['text'] = "Order number %s" % self.counter
class Barista(Tk):
def __init__(self):
Tk.__init__(self) # create the main window
self.title("Barista")
self.barista = Label(self, text="Barista Page", width=40)
self.barista.pack(side=TOP)
self.dashboard = Label(self, text="Customer Queue System")
self.dashboard.pack(side=TOP)
self.customer = Customer(self) # instantiate Customer window
self.mainloop()
Barista()

Python widgets and button

I'm trying to add a "Done" button to my program that will print the content of both Entry widgets to a new box. I can get the button to appear, but I can't get the information to show up in a new box. What am I doing wrong?
from Tkinter import *
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.grid()
self._name = StringVar()
self._name.set("Enter name here")
self._age = IntVar()
self._age.set("Enter age here")
top = self.winfo_toplevel() # find top-level window
top.title("Entry Example")
self._createWidgets()
self._button = Button(self,
text = "Done")
self._button.grid(row = 1, column = 0, columnspan = 2)
def _createWidgets(self):
textEntry = Entry(self, takefocus=1,
textvariable = self._name, width = 40)
textEntry.grid(row=0, sticky=E+W)
ageEntry = Entry(self, takefocus=1,
textvariable = self._age, width = 20)
ageEntry.grid(row=1, sticky=W)
def _widget(self):
tkMessageBox.showinfo
# end class Application
def main():
Application().mainloop()
You need to assign an action to your button using command: option.
To get what is written in Entry you need to use get() method.
showinfo you need two arguments, one is the title, the other one is what is going to be shown.
Also you need to import tkMessageBox.
Here is a working example.
import Tkinter as tk
import tkMessageBox
class Example(tk.Frame):
def __init__(self,root):
tk.Frame.__init__(self, root)
self.txt = tk.Entry(root)
self.age = tk.Entry(root)
self.btn = tk.Button(root, text="Done", command=self.message)
self.txt.pack()
self.age.pack()
self.btn.pack()
def message(self):
ent1 = self.txt.get()
ent2 = self.age.get()
tkMessageBox.showinfo("Title","Name: %s \nAge: %s" %(ent1,ent2))
if __name__=="__main__":
root = tk.Tk()
root.title("Example")
example = Example(root)
example.mainloop()

calling objects at tkinter frame

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.

Categories

Resources