I want to get an integer from an entry field and create new entry boxes below that. I have written a code to do that using a button. However, I want to make it happen automatically without a button as I entered the number, the rows update.
I saw one way to automate it is using the callback
.
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update():
for i in range(1, n_para.get() 1):
entryX = Entry(root)
entryX.grid(row=i 1, column=0)
entryY = Entry(root)
entryY.grid(row=i 1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i 1, column=2)
button1 = Button(root, text="update", command=update)
button1.grid(row=1, column=0)
root.mainloop()
So, I changed the code to the below one using callback
.
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update(*args):
try:
for i in range(1, n_para.get() 1):
entryX = Entry(root)
entryX.grid(row=i 1, column=0)
entryY = Entry(root)
entryY.grid(row=i 1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i 1, column=2)
except ValueError:
return
n_para.trace_add('write', update)
root.mainloop()
When I enter a number, it works and an error raises: _tkinter.TclError: expected floating-point number but got ""
which I don't know what is that for.
Also, the code only works when I put numbers in ascending format. forexample, if I first enter 5, then change it to 3 it doesn't work.
CodePudding user response:
You should use StringVar to associate with the Entry, as the entry contains text.
There is a method in StringVar to trace any changes: StringVar().trace(). Se example code below:
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = StringVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update(*args):
print('update', n_para.get())
n_para.trace('w', update) # Trace changes in n_para and run update if detected
root.mainloop()
The error you get is because the Entry contains text. You will have to convert it to int before you use it.
New example
You could do this in many ways, but here is one example:
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = StringVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
row_list = [] # List of all currently displayed entry rows
# and each row is a list of entrys within this list
def update(*args):
try:
para = int(n_para.get())
except ValueError:
return # Return without changes if ValueError occurs
rows = len(row_list)
diff = para - rows # Compare old number of rows with entry value
if diff == 0:
return # Return without changes
elif diff > 0: # Add rows of entrys and remember them
for row in range(rows 1, rows diff 1):
entry_list = [] # Local list for entrys on this row
for col in range(3):
e = Entry(root)
e.grid(row=row, column=col)
entry_list.append(e) # Add entry to list
row_list.append(entry_list) # Add entry list to row
elif diff < 0: # Remove rows of entrys and froget them
for row in range(rows-1, rows-1 diff, -1):
for widget in row_list[row]:
widget.grid_forget()
widget.destroy()
del row_list[-1]
n_para.trace('w', update) # Trace changes in n_para
root.mainloop()
Is that what you had in mind?