How can I delete a Python-Tkinter def LabelFrame? - python

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.

Related

Is there a way to toggle/hide/show tkinter buttons

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

Can I combine two bindings?

I want to update a widgets on a canvas widget when the window is resized. You can bind a function call on window resize via the <Configure> flag:
window.bind("<Configure>",resize)
However, this calls resize continuously while the window is being updated, many times per second. What would be better is if I could call resize after the window has been resized. So I imagine, once MB1 has been released.
So can I combine bindings? I need to combine both <Configure> and <ButtonRelease-1>
I was thinking of creating a global variable that contains the state of MB1, and updating this state via <ButtonRelease-1> and <ButtonPress-1> but I'm wondering if there's a lass hacky method.
A simple solution is to not do the work immediately, but instead schedule it for some time in the future. Each time the <Configure> event is handled you can cancel any previously scheduled work before scheduling the work again.
The following example shows how to update a label in the middle of a frame on <Configure>, but only after the window size hasn't changed for 200ms.
import tkinter as tk
def handle_configure(event):
global after_id
if after_id:
event.widget.after_cancel(after_id)
after_id = event.widget.after(200, update_label)
def update_label():
width = root.winfo_width()
height = root.winfo_height()
text = f"Size: {width}x{height}"
label.configure(text=text)
root = tk.Tk()
frame = tk.Frame(root, width=400, height=400)
frame.pack(fill="both", expand=True)
label = tk.Label(frame, text="")
label.place(relx=.5, rely=.5, anchor="c")
after_id = None
frame.bind("<Configure>", handle_configure)
root.mainloop()

Python: How to destroy buttons with the same name (tkinter)

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

How to delete buttons on Tkinter?

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.

Clear the window in tkinter

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.

Categories

Resources