I really need to be able to delete a button onscreen into a label. All I need to do is remove the button, and put the label in place of it. However, I do not know how to remove buttons.
I am running Windows 10, Python 3.9.2.
Are you looking for something like this?:
import tkinter as tk
def remove_button():
global label
# Get the grid parameters passed in button when it was created
button_grid_info = button.grid_info()
button.grid_forget()
label = tk.Label(button_grid_info["in"], text="This is a Label widget")
# Put the label exactly where the button was:
label.grid(**button_grid_info)
root = tk.Tk()
button = tk.Button(root, text="Click me", command=remove_button)
button.grid(row=1, column=1)
root.mainloop()
grid_forget removes the widget without destroying it. If you used <button>.pack, use pack_forget. If you used <button>.place, use place_forget.
Related
I am making blackjack in tkinter and instead of placing buttons over the existing buttons i want to toggle them when, say a new game.
There are many ways of doing this. One option (I think he simplest one) is to get your buttons in a frame that you can pack and unpack using pack and packing_forget. In this case you need another frame where your button frame is the only packed widget, so the buttons will appear in the same place when you pack them again. You can also resize the frame so things on it will become invisible when it becomes really small. Another option is to use a canvas where your buttons are canvas objects. You can them move or hide them as you want.
In addition to #Flavio Moraes answer you can use grid_remove() method to save a widget before remove it (if you don't need it anymore you can also destroy() the widget:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry("300x80")
root.title('Toogle button')
def crea():
""" restore button """
btn.grid(column=0, row=0, sticky='nsew')
def remo():
"""remove button"""
btn.grid_remove()
def btn_off():
btn.after(1500, remo)
btn.after(3000, crea)
btn = ttk.Button(root, text='Hide', command=btn_off)
btn.grid(column=0, row=0, rowspan=2, sticky='nsew')
root.columnconfigure(0, weight=3)
root.mainloop()
The loop in the program created a number of buttons with the same name. How to destroy them?
For example:
for i in range(5):
global btn
btn=Button(text=name,command=startfile_)
btn.place(x=5,y=5)
def destroy_it():
btn.destroy()#Its destroying only 1
destroy_btn(text=name,command=destroy_it)
It strongly depends on your use case. By the way, I suggest you to ensure your code is reproducible as-is, so that we can adapt our answers to your specific case.
Here some ways to address your problem.
1. save all buttons in a list and iterate over the list to delete them
pros: very easy to use and understand
cons: you need to pass your list along the code to work on it
import tkinter as tk
root = tk.Tk()
buttons = []
for i in range(5):
btn = tk.Button(root, text=f'test{i}', command=None) # TODO fill with your command
btn.pack()
buttons.append(btn)
def destroy_it(buttons):
# You must know the list of buttons to destroy
for btn in buttons.copy():
btn.destroy()
buttons.remove(btn) # also delete buttons from the list
tk.Button(root, text="Destroy all buttons", command=lambda: destroy_it(buttons)).pack()
root.mainloop()
2. destroy all widgets that satisfy a specific rule (i.e. Buttons with a specific text)
pros: you have a large flexibility on the widgets you are going to delete
cons: you may accidentally delete widgets, you must correctly deal with it
import tkinter as tk
root = tk.Tk()
for i in range(5):
btn = tk.Button(root, text=f'test{i}', command=None) # TODO fill with your command
btn.pack()
def destroy_it():
# Iterate over any widget and destroy it if it is a button with text "test....."
for child in root.winfo_children():
if isinstance(child, tk.Button) and child['text'].startswith('test'):
child.destroy()
tk.Button(root, text="Destroy all buttons", command=destroy_it).pack()
root.mainloop()
3. Give your buttons a name and address them by name
pros: easy to include in the code and to understand
cons: you must remember the names you used and you may get KeyError
import tkinter as tk
root = tk.Tk()
for i in range(5):
btn = tk.Button(root, name=f'btn{i}', text=f'test{i}', command=None) # TODO fill with your command
btn.pack()
def destroy_it():
# Get each button by its name
for i in range(5):
btn = root.nametowidget(f'.btn{i}')
btn.destroy()
tk.Button(root, text="Destroy all buttons", command=destroy_it).pack()
root.mainloop()
There are probably many other ways to achieve it, such as associating an "autodestroy" method to each button that is triggered by command, or include your buttons in a Frame and destroy the frame at once... But you may start from the examples above
I am working on an app using Tkinter and I have a small question.
For example, I have a label placed like this:
Label = Label(root, text="Hello").place(x=5, y=5)
Is there any way to hide the label when a button is pressed or when a function is called?
Any help will be appreciated
Thanks!
You should simply never chain .place() or any other geometry manager to the widget creator. It returns None.
lbl_name = Label(root, text="Hello")
lbl_name.place(x=5, y=5)
Now you can handle lbl_name as a label object. To hide it you can use:
lbl_name.place_forget()
Unfortunately, now its gone. Therefore, first save the place properties:
lbl_name = Label(root, text="Hello")
lbl_name.place(x=5, y=5)
lbl_name.saved = lbl_name.place_info()
You can now show it again with:
lbl_name.place(lbl_name.saved)
Note: You can print lbl_name.saved. It is a dictionary with all place-properties of the lbl_name Label object.
I'm using buttons to call def variables that create labelframes. I'm switching between the buttons like tabs and want to display my new frames underneath respectively yet the old labelframe is left behind and is not defined to be called for erasing.
Here's an example of how i'm phrasing the code.
from tkinter import *
root = Tk()
root.state('zoomed')
def A1():
lf=LabelFrame(root,text='new frame')
lf.pack()
d=Button(lf, text='Added', width=0, borderwidth=3)
d.pack()
a = Button(root, text="add", command=A1)
a.pack()
b=Button(root,text="Delete me",command=lambda:b.pack_forget())
b.pack()
c=Button(root,text="Delete Added",command=lambda:lf.pack_forget())
c.pack()
root.mainloop()
Thank you for your time and advice.
You could:
Make a function to delete the frame.
Create the button with no command initially.
Set the button's command when the frame is created.
Then, when the frame is deleted, reset the button's command.
Such as this:
from tkinter import *
root = Tk()
root.state('zoomed')
# Added a function to delete the frame and reset the button's command
def remove_frame(lf):
lf.pack_forget()
c.config(command=None)
def A1():
lf=LabelFrame(root,text='new frame')
lf.pack()
d=Button(lf, text='Added', width=0, borderwidth=3)
d.pack()
# Sets the remove_frame function to the button's command.
# Since lf is created locally it will need to be passed to the remove_frame function.
c.config(command=lambda: remove_frame(lf))
a = Button(root, text="add", command=A1)
a.pack()
b=Button(root,text="Delete me",command=lambda:b.pack_forget())
b.pack()
c=Button(root,text="Delete Added") # Create the button with no command.
c.pack()
root.mainloop()
Currently this will allow you to add several frames, but only delete one.
If the goal is to only have one frame, disabling the add button until the frame is deleted would be the easiest option.
If you wanted to delete them sequentially or all of them, appending the frames to a list and using a pack_forget on each item in the list would be one method of accomplishing this.
I made a tkinter window in python with some widgets like so:
def createWidgets(self):
self.grid(padx=25, pady=25)
self.start = Button(self)
self.start["text"] = "Start"
self.start["width"] = "15"
self.start["height"] = "1"
self.start["command"] = self.start_g
self.start.grid(row=0, column=1, pady=5, sticky=N)
The problem is, I want to remove a widget, so I could add something else to this window. I tried remove() grid_forget() and I can get rid of the widget. Is there any way to remove a widget or wipe the window?
You can call grid_forget() on your widget to permanently remove it.
e.g
self.start.grid_forget()
If you wanted to clear the whole window then you could do the same on your main frame.