Search code examples
pythonuser-interfacetkinteriterationtkinter-entry

how do I create entry fields and buttons to get the content from the entry field using iteration in tkinter for python?


I'm trying to make a tkinter GUI with a certain amount of buttons and entry fields that is specified by the user, so in this code below for example if the user specifies the variable number to be 3 I want there to be 3 entry boxes and , and I want to set it up so that if I type a value into the first field and click the button next to it, I want that button to read the value from the entry field next to it. I also need to assign each entry field to a variable that will be created through the same iterative loop. However, I'm having difficulty especially in regards to mapping the buttons to the entry fields, as I always seem to run up against an error with the text "AttributeError: 'NoneType' object has no attribute 'get'". Would anyone be able to either fix my code or help me find an alternative solution to the problem? Sorry if the description's a bit confusing. This is different from just a problem of just getting the contents of the entry widget as I need it to create a certain amount of entry widgets and buttons using iteration, and the question that my question has been marked a duplicate of doesn't explain how to iteratively map each entry field to each button. For example, if I enter 3 as the variable, I need the program to create entry field 1, entry field 2 and entry field 3 and button 1, button 2 and button 3 and then map each button to its respective entry field using iteration. I've tried using dictionaries, but this doesn't seem to help much.

import tkinter as tk
root = tk.Tk()
number = 3
d={}
def callBack():
    print(d["E{0}".format(i)].get())
    return
for i in range(0,number):
    d["E{0}".format(i)] = tk.Entry(root)
    d["E{0}".format(i)].grid(row=i, column=0)
    d["B{0}".format(i)] = tk.Button(root, text="test", command=callBack)
    d["B{0}".format(i)].grid(row=i, column=1)

Solution

  • You need to save the Entry and Button before calling grid:

    import tkinter as tk
    
    number = 3
    root = tk.Tk()
    
    def get_on_click(widget_dict, entry_name):
        def on_click():
            result = widget_dict[entry_name].get()
            print("%s = %s" % (entry_name, result))
            return result
        return on_click
    
    d = dict()
    for i in range(0, number):
        entry_name = "E{0}".format(i)
        button_name = "B{0}".format(i)
        print(entry_name, button_name)
        d[entry_name] = tk.Entry(root)
        d[entry_name].grid(row=i, column=0)
        d[button_name] = tk.Button(root, text="test", command=get_on_click(d, entry_name))
        d[button_name].grid(row=i, column=1)
    
    root.mainloop()
    

    This should help you get started.

    In your comment, you ask how to save the value in the Entry. I would create a class to handle everything:

    import tkinter as tk
    
    number = 3
    root = tk.Tk()
    
    class EntryButton(object):
        def __init__(self, root, number):
            self.number = number
            self.entry = tk.Entry(root)
            self.button = tk.Button(root, text="test", command=self.on_click)
            self.entry.grid(row=number, column=0)
            self.button.grid(row=number, column=1)
            self.value = None
    
        def on_click(self):
            self.value = self.entry.get()
    
    storage = dict()
    for i in range(0, number):
        storage[i] = EntryButton(root, i)
    
    root.mainloop()
    
    for i in range(0, number):
        value = storage[i].value
        print(f"storage[{i}] = {value}")
    

    As you can see, this eliminates a lot of extra work.