You definitely don't want to use exec, and you don't need to use the textvariable parameter. Both of them just add to the confusion. Just save your widgets as a dictionary, get the data directly from the input widget, and everything becomes very easy to manage.
Here is a working example:
import tkinter as tk class Example(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) b = tk.Button(self, text="Done!", command=self.upload_cor) b.pack() table = tk.Frame(self) table.pack(side="top", fill="both", expand=True) data = ( (45417, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"), (45418, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"), (45419, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"), (45420, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"), (45421, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"), (45422, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"), (45423, "rodringof", "CSP L2 Review", 0.000394, "2014-12-19 10:08:12", "2014-12-19 10:08:12"), ) self.widgets = {} row = 0 for rowid, reviewer, task, num_seconds, start_time, end_time in (data): row += 1 self.widgets[rowid] = { "rowid": tk.Label(table, text=rowid), "reviewer": tk.Label(table, text=reviewer), "task": tk.Label(table, text=task), "num_seconds_correction": tk.Entry(table), "num_seconds": tk.Label(table, text=num_seconds), "start_time": tk.Label(table, text=start_time), "end_time": tk.Label(table, text=start_time) } self.widgets[rowid]["rowid"].grid(row=row, column=0, sticky="nsew") self.widgets[rowid]["reviewer"].grid(row=row, column=1, sticky="nsew") self.widgets[rowid]["task"].grid(row=row, column=2, sticky="nsew") self.widgets[rowid]["num_seconds_correction"].grid(row=row, column=3, sticky="nsew") self.widgets[rowid]["num_seconds"].grid(row=row, column=4, sticky="nsew") self.widgets[rowid]["start_time"].grid(row=row, column=5, sticky="nsew") self.widgets[rowid]["end_time"].grid(row=row, column=6, sticky="nsew") table.grid_columnconfigure(1, weight=1) table.grid_columnconfigure(2, weight=1) # invisible row after last row gets all extra space table.grid_rowconfigure(row+1, weight=1) def upload_cor(self): for rowid in sorted(self.widgets.keys()): entry_widget = self.widgets[rowid]["num_seconds_correction"] new_value = entry_widget.get() print("%s: %s" % (rowid, new_value)) if __name__ == "__main__": root = tk.Tk() Example(root).pack(fill="both", expand=True) root.mainloop()
I would actually implement this a little differently by creating a Table class using the add_row method, but I did not want to get too complicated. The basic idea is the same, regardless of whether you create the Table class, do it all in one class or do it procedurally - create a dictionary to represent your data. You can also use nested lists, but I believe dictionaries will be much easier to use. They are also self-documenting since you are referencing things by a symbolic name, and not just that column 4 is the start time.