1

Part of my program prompts the user to enter a sample number into an entry field, and then click a button which generates that number of entry widgets beneath it (to enter information about each sample). The entry widgets appear exactly as expected, one beneath the other for the entered number of samples. I can't figure out how to separate the variables for each of those new entry widgets now. I had hoped that each one would allow me to enter a different value, and then call them back via .get(). That's not the case, they ALL change together to whatever I type into one. Below is the section of code that I believe is the issue:

normval_f= IntVar()
    x= samp.get()
    f=1
    while f<=x:
        f_entry = ttk.Entry(mainframe, width=7, textvariable=normval_f)
        f_entry.grid(column=1, row=f+12)
        f_label = ttk.Label(mainframe, text="Sample "+str(f)+ " value").grid(column=2, row=f+12, sticky=W)
        f=f+1        
Ian
  • 33
  • 3

2 Answers2

0

A few suggestions; don't use a while loop, use a for loop instead. Secondly, I'd suggest storing each of your variables inside a list, or as I have done, in a list. At the moment, you are overwriting your variables each time you go through the loop so you need to create a new one each time and store it somewhere.

Here is an example of storing a number of fields in a dictionary.

from tkinter import *

class App(Frame):
    def __init__(self,master):
        Frame.__init__(self, master)
        fields = ['name','age','gender']
        self.field_variables = {}
        for idx,field in enumerate(fields):
            self.field_variables[field] = StringVar()
            f_entry = Entry(self,textvariable=self.field_variables[field])
            f_entry.grid(column=2,row=idx)
            f_label = Label(self,text=field)
            f_label.grid(column=1,row=idx)

        go_btn = Button(self,text="Go",command=self.get_all)
        go_btn.grid()

    def get_all(self):
        print(self.field_variables)

if __name__ == '__main__':
    root = Tk()
    app = App(root)
    app.grid()
scotty3785
  • 6,763
  • 1
  • 25
  • 35
  • You are missing `root.mainloop()` and your print statement does not print out the values of each field but instead the StringVar object location. – Mike - SMT Aug 02 '17 at 18:06
0

List and Dictionaries can be very useful when dealing with large amounts or potently large amounts of widgets.

Below is a bit of code to accomplish what you described in your question.

I use a list called self.my_entries to store all the entries that will be created based on the value of what the user types in. I also added a little error handling just in case the user tries to type in something other than a number or nothing is enter when the button is pressed.

The first entry and button are placed on the root window and for all of the entry fields that are going to be created we add a frame below the first button. This will allow us to manage the entry fields a bit easier if we want to reset the field later.

from tkinter import *


class Example(Frame):


    def __init__(self):
        Frame.__init__(self)

        self.pack()   
        self.my_entries = []

        self.entry1 = Entry(self)
        self.entry1.grid(row = 0, column = 0)
        Button(self, text="Set Entry Fields", command=self.create_entry_fields).grid(row = 1, column = 0)

        self.frame2 = Frame(self)
        self.frame2.grid(row = 2, column = 0)

    def create_entry_fields(self):
        x = 0
        try:
            x = int(self.entry1.get())
            if x != 0:
                for i in range(x):
                    self.my_entries.append(Entry(self.frame2))
                    self.my_entries[i].grid(row=i, column=1)
                    f_label = Label(self.frame2, text="Label {}: ".format(i+1))
                    f_label.grid(row=i, column=0)
            Button(self.frame2, text="Print to console", command=self.print_all_entries).grid(row=x, column=0, sticky = "nsew")
            Button(self.frame2, text="Reset", command=self.clear_frame2).grid(row=x, column=1, sticky = "nsew")
        except:
            print("Invalid entry. Only numbers are allowed.")

    def print_all_entries(self):
        for i in self.my_entries:
            print(i.get())

    def clear_frame2(self):
        self.my_entries = []
        self.frame2.destroy()
        self.frame2 = Frame(self)
        self.frame2.grid(row = 2, column = 0)


if __name__ == '__main__':
    root = Tk()
    test_app = Example()
    root.mainloop()

Let me know if you have any questions about the above code.

Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • wow! Thank you so much for this. With a few edits this fit just about perfect into my scheme. Can't thank you enough!! – Ian Aug 02 '17 at 19:39
  • @Ian: Glad to help. – Mike - SMT Aug 02 '17 at 20:00
  • Just a thought but if it's too tricky it's not big deal. Is there a way to add a scrollbar to that if the number of entry widgets exceeds the screen size? I can't seem to pinpoint the way of achieving that for multiple widgets... – Ian Aug 02 '17 at 21:17
  • @Ian: You can but you would need to use a canvas that has an embedded frame with the widgets inside of it. Take a look at [this post](https://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-group-of-widgets-in-tkinter) – Mike - SMT Aug 02 '17 at 21:55
  • ok I"ll have to look into that... thanks again @sierra mountain tech – Ian Aug 08 '17 at 14:42