0

I have many tkinter entries named idn1 to idn5,instead of repeating the same delete function for every entry I tried the following which went well with visual basic but not python:

def deleteme():
    
    idn = ""
    i = 1
    while True:
    
        idn ="idn"+str(i)+".delete(0,END)"
        
        i += 1
        idn
        
        if i == 6:
            break
    return True

root = Tk()

root.geometry('{}x{}'.format(460, 350))

idn1 = Entry(root).grid(row =0,column=1)

idn2 = Entry(root).grid(row =1,column=1)

idn3 = Entry(root).grid(row =2,column=1)

idn4 = Entry(root).grid(row =3,column=1)

idn5 = Entry(root).grid(row =4,column=1)

btn1 = Button(root,command = deleteme)

root.mainloop()  
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • [Does this help you?](https://stackoverflow.com/questions/701802/how-do-i-execute-a-string-containing-python-code-in-python) Also, as an alternative: How about storing your objects in an array / list? Then you could just iterate over them. – DJSchaffner Feb 11 '21 at 12:37
  • Thank you, I tried this before but didn't work with me – S Kalib Feb 11 '21 at 12:42
  • keep widgets on list and then yoy need only `for`-loop to delete them . In current version you create strings like `"idn0.delete(0,END)"` but for Python it is only string, nothing more. It will not run it as command. You would need to use `eval("idn0.delete(0,END)")` but it is not preferred. There are other methods. Keep items on list or in dictionary and use `for`-loop – furas Feb 11 '21 at 18:47

2 Answers2

0

You create strings like "idn0.delete(0,END)" but for Python it is only string, nothing more. It will not run it as command. You would need to use eval("idn0.delete(0,END)") to execute command in this string but eval() is not preferred method.

You should keep widgets on list or in dictionary and then you can use for-loop to delete all items.


But firt other very common mistake

Using

variable = Widget().grid()

you assign None to variable because grid()/pack()/place() return None

You have to do it in two steps

variable = Widget()
variable.grid()

Minimal working code

import tkinter as tk  # PEP8: `import *` is not preferred

# --- functions ---
 
def deleteme():
    
    for item in widgets:
        item.delete(0, 'end')
        
# --- main ---

widgets = []

root = tk.Tk()

for number in range(5):
    variable = tk.Entry(root)
    variable.grid(row=number, column=1)
    widgets.append(variable)
    
btn1 = tk.Button(root, text='Delete', command=deleteme) # PEP8: inside `()` use space after comma `,` but without spaces around `=`
btn1.grid(row=5, column=1)

root.mainloop() 

The same with dictionary

import tkinter as tk  # PEP8: `import *` is not preferred

# --- functions ---
 
def deleteme():
    
    for name, item in widgets.items():
        item.delete(0, 'end')
        
# --- main ---

widgets = {}

root = tk.Tk()

for number in range(1, 6):
    variable = tk.Entry(root)
    variable.grid(row=number, column=1)
    widgets[f"idn{number}"] = variable
    
btn1 = tk.Button(root, text='Delete', command=deleteme) # PEP8: inside `()` use space after comma `,` but without spaces around `=`
btn1.grid(row=5, column=1)

root.mainloop() 

Of course you can add widgets manually without for-loop but this it is long and boring so I skip some widgets. But even if I skip or add widgets I don't have to change code in deleteme()

import tkinter as tk  # PEP8: `import *` is not preferred

# --- functions ---
 
def deleteme():
    
    for name, item in widgets.items():
        item.delete(0, 'end')
        
# --- main ---

widgets = {}

root = tk.Tk()

variable = tk.Entry(root)
variable.grid(row=0, column=1)
widgets["idn1"] = variable

# or 

widgets["idn2"] = tk.Entry(root)
widgets["idn2"].grid(row=1, column=1)
    
widgets["idn3"] = tk.Entry(root)
widgets["idn3"].grid(row=2, column=1)
    
# etc.    
    
btn1 = tk.Button(root, text='Delete', command=deleteme) # PEP8: inside `()` use space after comma `,` but without spaces around `=`
btn1.grid(row=5, column=1)

root.mainloop() 
furas
  • 134,197
  • 12
  • 106
  • 148
  • Thank you very much, I found your answer very helpful, I appreciate your genuine help, it solved many problems in my app and gave me a great push, thank you again. – S Kalib Feb 11 '21 at 19:23
0

The simplest solution, assuming your UI design supports it, is to put all of the entry widgets in a frame. You can then delete the frame and all of its children will automatically be deleted.

entry_frame = Frame(root)
idn1 = Entry(entry_frame).grid(row =0,column=1)
idn2 = Entry(entry_frame).grid(row =1,column=1)
idn3 = Entry(entry_frame).grid(row =2,column=1)
idn4 = Entry(entry_frame).grid(row =3,column=1)
idn5 = Entry(entry_frame).grid(row =4,column=1)
...
# this destroys the frame and all of its children
entry_frame.destroy()

If you can't do that or don't want to do that, the next best solution is to store the widgets in a list.

For example, you can create them in a list like so:

entries = []
for row in range(5):
    entry = Entry(root)
    entry.grid(row=row, column=1)
    entries.append(entry)

Of course, you don't have to create them in a loop. That works well if the widgets are largely identical. If each needs to be unique, create then individually and then append them to the list.

idn1 = Entry(root)
idn2 = Entry(root)
idn3 = Entry(root)
idn4 = Entry(root)
idn5 = Entry(root)
entries = [idn1, idn2, idn3, idn4, idn5]

Note: regardless of which method you choose, you must put the call to grid in a separate statement. The way you wrote your original code, all of your entry variables will be set to None since that's what grid returns.

However you create the list, you can delete them by iterating over the list:

for entry in entries:
    entry.destroy()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you indeed, I also tried your suggestion and found it very useful in term of uniquness of each widget. – S Kalib Feb 12 '21 at 06:47