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.
Advertisement
Answer
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?