I would like to delete an object from another class and make it invisible.
For example a class with a button called Button 1.
Another class with a button called Button 2.
When I click on Button 2 I don't want to see Button 1.
from tkinter import*
class Menu(Frame):
def __init__(self,master):
Frame.__init__(self,master,bg = "white")
self.grid()
self.button_clicks = 0
self.create_widgets()
def create_widgets(self):
self.button = Button(self)
self.button["text"] = "Button 1: 0"
self.button["command"] = self.update_count
self.button.grid(ipadx = 5, padx = 150)
def update_count(self):
self.button["text"] = "Another try: " + str(self.button_clicks)
self.button_clicks += 1
if self.button_clicks > 10:
self.button_clicks = 0
class noMenu(Frame):
def __init__(self,master):
Frame.__init__(self,master,bg = "white")
self.grid()
self.button_clicks = 0
self.create_widgets()
def create_widgets(self):
self.button = Button(self)
self.button["text"] = "Bye button 1"
self.button["command"] = self.byeMenu
self.button.grid(ipadx = 5, padx = 150)
def byeMenu(self):
Menu.grid_forget()
app = Tk()
app.configure(background= "white")
app.title("Button on my but")
app.geometry("400x200")
first = Menu(app)
second = noMenu(app)
app.mainloop()
If you want widgets to interact use the fact that they have common ancestry to achieve this. Then if you want a widget to "disappear" you can do so with the geometry manger you are using
An example to work from might be:
import Tkinter
class Main(Tkinter.Tk):
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
self.first = Menu(self)
self.second = noMenu(self)
def first_button_response(self):
self.first.button.pack_forget()
class noMenu(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
self.button = Tkinter.Button(
self, text="Bye button 1", command=parent.first_button_response
)
self.button.pack()
self.pack()
class Menu(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
self.button = Tkinter.Button(self, text="Button 1")
self.button.pack()
self.pack()
if __name__ == "__main__":
app = Main(None)
app.mainloop()
Here I used pack_forget to remove the first button. If you want to use the grid manager you should look into grid_remove or grid_forget depending on whether you want to at some point have the button reappear or not.
Related
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
I want to change the configurations on one of my labels, but cannot figure out how to reference it in a function outside of the class. My goal is to crate a function that will be placed in a loop to check the value of "my_turn". Depending on the value of "my_turn", I want to change the configuration of "self.turn" label in the "TeamFrame" class, however I can't figure out how to reference it outside of the class.
class LoginScreen(tk.Canvas):
def __init__(self, parent):
tk.Canvas.__init__(self, parent)
self.parent = parent
self.create_image(0, 0, image=my_img, anchor="nw")
self.button = tk.Button(self.frame, text="Connect", bg='burlywood3', activebackground='burlywood3', font="12",
command=lambda: login())
self.button.grid(row=4, columnspan=3, pady=10)
def login():
my_name = self.entry.get()
msg = str(my_name)
client.send(msg.encode(FORMAT))
self.destroy()
root.title(f"Main Application - {my_name}")
draft = MainApplication(root, my_name)
draft.pack(side="top", fill="both", expand=True)
threading.Thread(target=start_app).start()
class MainApplication(tk.Canvas):
def __init__(self, parent, name):
tk.Canvas.__init__(self, parent)
self.parent = parent
self.create_image(0, 0, image=my_img, anchor="nw")
self.team = TeamFrame(self, 1, 4, name)
class TeamFrame(tk.Frame):
def __init__(self, parent, r, c, name):
tk.Frame.__init__(self, parent)
self.parent = parent
self.configure(bd=1, relief="ridge", bg='wheat3')
self.grid(row=r, rowspan=2, column=c, padx=10, pady=15, sticky=tk.NE)
self.turn = tk.Label(self, bg='wheat3', text=f"You are not on the clock.\n ",
fg='gray28', font='bold 12', disabledforeground='red3')
self.turn.pack(pady=10)
def start_app():
# threaded loop that check "my_turn" and update lists and execute additional game functions
if __name__ == "__main__":
plr.sort_players(sort_method)
root = tk.Tk()
root.minsize(400, 300)
root.title(f"Login")
root.iconbitmap('football.ico')
my_img = ImageTk.PhotoImage(file='field.gif')
LoginScreen(root).pack(side="top", fill="both", expand=True)
root.mainloop()
You can pass the instance of MainApplication, draft, to start_app():
threading.Thread(target=start_app, args=(draft,)).start()
Then you can access the required label via main_app.team.turn (main_app is the name of the new argument of start_app()) as below:
def start_app(main_app):
# do something
main_app.team.turn['text'] = 'Hello'
# do other stuff
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()
How would I create a new window when the user clicks a button (still needs creating)? I have took some code out to make this shorter. I need a button creating and when they hit that button, a new window opens. I haven't created the button because the button has to be linked to the new window. Please help
My imports...
class App:
def __init__(self, master):
self.master = master
# call start to initialize to create the UI elemets
self.start()
def start(self):
self.master.title("E-mail Extranalyser")
self.now = datetime.datetime.now()
tkinter.Label(
self.master, text=label01).grid(row=0, column=0, sticky=tkinter.W)
# CREATE A TEXTBOX
self.filelocation = tkinter.Entry(self.master)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=0, column=1)
# CREATE A BUTTON WITH "ASK TO OPEN A FILE"
# see: def browse_file(self)
self.open_file = tkinter.Button(
self.master, text="Browse...", command=self.browse_file)
# put it beside the filelocation textbox
self.open_file.grid(row=0, column=2)
# now for a button
self.submit = tkinter.Button(
self.master, text="Execute!", command=self.start_processing,
fg="red")
self.submit.grid(row=13, column=1, sticky=tkinter.W)
def start_processing(self):
#code here
def browse_file(self):
# put the result in self.filename
self.filename = filedialog.askopenfilename(title="Open a file...")
# this will set the text of the self.filelocation
self.filelocation.insert(0, self.filename)
root = tkinter.Tk()
app = App(root)
root.mainloop()
Use a Toplevel to open a new one. Modify your code as shown below.
self.NewWindow = tkinter.Button(self.master,
text="New Window",
command=self.CreateNewWindow)
def CreateNewWindow(self):
self.top = tkinter.Toplevel()
self.top.title("title")
Take a look at https://www.youtube.com/watch?v=jBUpjijYtCk. Working through this tutorial would probably help you but this specific video shows how to work with multiple pages.
Something like this:
from tkinter import *
class Sample(Tk):
def __init__(self,*args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = Frame(self)
container.pack(side="top", fill="both", expand = True)
self.frames = {}
for F in (MainPage, OtherPage):
frame=F(container, self)
self.frames[F]=frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(MainPage)
def show_frame(self, page):
frame = self.frames[page]
frame.tkraise()
class MainPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
Label(self, text="Start Page").pack()
Button(self, text="other page?", command=lambda:controller.show_frame(OtherPage)).pack()
class OtherPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
Label(self, text="Next Page").pack()
Button(self, text="back", command=lambda:controller.show_frame(MainPage)).pack()
app = Sample()
app.mainloop()
Similar questions have been asked, but none of them address the particular way my script is constructed:
from Tkinter import *
from ttk import *
class Gui(Frame):
def __init__(self, parent):
Frame.__init__(self, parent) #Gui inherits from built in Frame Class
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Shoes Ware")
self.pack(fill=BOTH, expand=1)
run_val = Entry(self)
run_val["width"] = 5
run_val.place(x=80, y=40)
quit_B = Button(self, text="Submit", command=self.submit)
quit_B.place(x=130, y=170)
def submit(self):
value = run_val.get()
print value
self.quit()
def main():
root = Tk()
root.geometry("300x200+50+50")
app = Gui(root)
root.mainloop()
if __name__ == '__main__':
main()
I get "NameError: global name 'run_val' is not defined" when I hit the submit button. What am I doing wrong here. Right now the print statement is just to check my work. Later on, I'll be using that value in a program.
You are not storing the reference to the Entry widget in initUI.
def initUI(self):
# ...
self.run_val = Entry(self)
self.run_val["width"] = 5
self.run_val.place(x=80, y=40)
Then you can retrieve the value of self.run_val.get() without any problem.