Mr K
Mr K

Reputation: 121

How to create Tkinter widgets with loop and assign custom functions to each of them?

This is my first python app and I'm aware of many of it's flaws so I'll try to learn on my mistakes.

I would like to understand how to shorten my code a bit by putting declaration of tkinter widgets in a loop.

Here is part of the code(there is quite large list of similar sections, but I would just apply same logic):

varplies = StringVar(root)
varnotch = StringVar(root)
varspreader = StringVar(root)
varorder1 = StringVar(root)
varorder2 = StringVar(root)
def pliesto_uppercase(*args):
    varplies.set(varplies.get().upper())

def notchto_uppercase(*args):
    varnotch.set(varnotch.get().upper())

def spreaderto_uppercase(*args):
    varspreader.set(varspreader.get().upper())

def order1to_uppercase(*args):
    varorder1.set(varorder1.get().upper())

def order2to_uppercase(*args):
    varorder2.set(varorder2.get().upper())

varplies.trace_add('write', pliesto_uppercase)
varnotch.trace_add('write', notchto_uppercase)
varspreader.trace_add('write', spreaderto_uppercase)
varorder1.trace_add('write', order1to_uppercase)
varorder2.trace_add('write', order2to_uppercase)
self.rnplies_entry = Entry(self.entry_frame, background=rgbcon2((158, 174, 179)),
                           justify='center', textvariable=varplies, width=4)
self.rnnotch_entry = Entry(self.entry_frame, background=rgbcon2((158, 174, 179)),
                           justify='center', textvariable=varnotch, width=4)
self.rnspreader_entry = Entry(self.entry_frame, background=rgbcon2((158, 174, 179)),
                              justify='center', textvariable=varspreader, width=4)
self.rnorder1_entry = Entry(self.entry2_frame, background=rgbcon2((158, 174, 179)),
                            justify='center', textvariable=varorder1, width=8)
self.rnorder2_entry = Entry(self.entry2_frame, background=rgbcon2((158, 174, 179)),
                            justify='center', textvariable=varorder2, width=8)
self.rnplies_entry.grid(column=1, row=5, padx=5, sticky="SEW")
self.rnnotch_entry.grid(column=2, row=5, padx=5, sticky="SEW")
self.rnspreader_entry.grid(column=5, row=5, padx=5, sticky="SEW")
self.rnorder1_entry.grid(column=0, row=9, padx=5, pady=5, sticky="SEW")
self.rnorder2_entry.grid(column=0, row=10, padx=5, pady=5, sticky="SEW")



pfdate = StringVar(root)
pfdate.set('All')
pfmarker = StringVar(root)
pfmarker.set('All')
pfdate.trace('w', partial(changeplan, widget=pfdate))
pfmarker.trace('w', partial(changeplan, widget=pfmarker))
def planfilters():
    pdatelist = plandatefilter()
    pmarkerlist = planmarkerfilter()
    self.drop_datepl = OptionMenu(self.optionplan_frame, pfdate, *pdatelist)
    self.drop_datepl.config(bg=rgbcon2((39, 46, 46)), width=10, fg='white')
    self.drop_datepl.grid(row=5, column=0, sticky="E", padx=5, pady=5)
    self.drop_rnpl = OptionMenu(self.optionplan_frame, pfmarker, *pmarkerlist)
    self.drop_rnpl.config(bg=rgbcon2((39, 46, 46)), width=22, fg='white')
    self.drop_rnpl.grid(row=5, column=1, sticky="E", padx=5, pady=5)

In short, I would like to understand how to put it in the loop to be like for example:

pl_filters = ('pfdate', 'pfmarker')
for opt_item in pl_filters:
    pl_filters[opt_item] = StringVar(root)
    pl_filters[opt_item].set('All')
    pl_filters[opt_item].trace('w', partial(changeplan, widget=pl_filters[opt_item]))

Upvotes: 0

Views: 164

Answers (1)

Henry Yik
Henry Yik

Reputation: 22493

Judging from the first part of your code, it looks like you are using the trace method on your StringVar just to convert the inserted characters to upper case. If so, I recommend implementing your own class with such method built in so you can avoid the need to create them later.

Also, you can create your StringVar and Entry in a for loop. Just save those references in a list for later use if required.

import tkinter as tk

root = tk.Tk()

class CustomVar(tk.StringVar):
    def __init__(self):
        tk.StringVar.__init__(self)
        self.trace("w",self.trace_method)

    def trace_method(self,*args):
        self.set(self.get().upper())

class Something(tk.Frame):
    def __init__(self,master=None,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        all_vars = [CustomVar() for _ in range(5)] #create 5 vars in one go
        entries = []
        for num, var in enumerate(all_vars,1): #loop through the vars and create entries
            entry = tk.Entry(self,background="yellow",justify="center",
                             textvariable=var,width=4 if num <4 else 8)
            entries.append(entry)

        for num, cords in enumerate(((1,5),(2,5),(5,5),(0,9),(0,10))): #your grid row and column number grouped in a tuple
            entries[num].grid(column=cords[0],row=cords[1],padx=5,sticky="SEW")

a = Something(root)
a.pack()

root.mainloop()

Upvotes: 1

Related Questions