Search code examples
pythontkintertrace

Is there a way to get values of dynamically added text fields in tkinter?


For homework, I have to create an application that creates a text field everytime a user clicks a button, and then get values from the fields when "submit" button is pressed. The trace method shows up repeatedly, but I do not know how to use it. I know it requires a callback function, but what should that callback function be?

from tkinter import *
from tkinter import ttk
import sqlite3
import getpass
import wipComingIn

class Application(object):
    def __init__(self,master):
        self.master=master
        self.ScanWIPIn = Button(master, text="Scan WIP In", width=25,         
font='Calibri 12 
bold',background='snow',command=self.scanWIPIn).grid(row=0, column=0, 
padx=10)

def scanWIPIn(self):
    incomingInventory=wipComingIn.scanIn()

def main():
    root = Tk()
    app=Application(root)
    root.title("Main Menu")
    root.configure(background="light cyan")
    root.resizable(0, 0)
    root.geometry('230x230+300+80')
    root.mainloop()

if __name__=='__main__':
    main()

class scanIn(Toplevel):

    def __init__(self):
        Toplevel.__init__(self)
        self.geometry('300x100+350+100')
        self.title('Scan In')
        self.resizable(0,0)
        self.num_rows=1
        self.LocationLb = Label(self,text='Scan Location:',font='Arial 
12').grid(row=1,column=1)
        self.LocationBCText = Entry(self).grid(row=1,column=2)
        self.AddLotBtn= Button(self,text="Scan 
Lot",command=self.addField).grid(row=2,column=1)
        self.CompleteTransaction = 
Button(self,text="Complete",command=self.AddEntry).grid(row=2,column=4)

    global listOfLots
    listOfLots=[]
    listOfLocation=[]
    global rowNum
    rowNum=2

def addField(self):
    height =Toplevel.winfo_height(self)
    height=height+25
    global rowNum
    rowNum=rowNum+1
    listOfLots.append(StringVar())

    newLot = Entry(self, textvariable=listOfLots[rowNum - 2])

    newLot.grid(row=rowNum,column=2, pady=1)
    listOfLots.append(StringVar())
    geometryText='300'+str(height)+'350+100'
    print(geometryText)
    self.geometry('300x'+str(height)+'+350+100')
    newLot.focus_set()

Solution

  • You could try just making a class that does it, for example:

    import tkinter as tk
    from tkinter import ttk
    
    root = tk.Tk()
    root.geometry('200x200')
    
    class EntryListWidget(ttk.Frame):
        """Widget that creates a column of entry boxes."""
        def __init__(self, master):
            super().__init__(master)
            self.entries = []
    
        def add_entry(self):
            """Creates a new entry box and keeps reference to respective variable."""
            entry_var = tk.StringVar()
            self.entries.append(entry_var)
            ttk.Entry(self, textvariable=entry_var).pack()
    
        def get_entries(self):
            """Gets each entrybox text and returns as list."""
            return [entry.get() for entry in self.entries]
    
    entry_widget = EntryListWidget(root)
    entry_widget.pack()
    
    # Buttons to control adding new entry and getting their values
    ttk.Button(root, text='Add Entry', command=entry_widget.add_entry).pack()
    ttk.Button(root, text='Get Entries', command=entry_widget.get_entries).pack()
    
    root.mainloop()
    

    Just using the variable classes and not trace; I actually wouldn't use trace in this situation because I believe trace uses the callback every time the variable changes and here you have a one time "submit" button that collects all the values. You could extend this class idea to get what you're looking to do I bet.